From 238f1e66fa771370986ffec135ffc4b935c2c4d6 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Fri, 5 Apr 2024 15:36:16 -0500 Subject: [PATCH 01/37] end to end testing --- .env.sample | 9 + .github/workflows/main.yml | 20 + .gitignore | 3 + Dockerfile | 44 + Dockerfile-db | 8 + README.md | 48 +- application/controllers/User_options.php | 4 + application/views/view_log/partial/log.php | 2 +- application/views/view_log/qso.php | 2 +- cypress.config.js | 11 + cypress/e2e/1-login.cy.js | 22 + cypress/e2e/2-version-info.cy.js | 46 + cypress/e2e/3-qso.cy.js | 47 + cypress/support/commands.js | 8 + cypress/support/e2e.js | 20 + docker-compose.yml | 25 + install/index.php | 8 +- package-lock.json | 1981 ++++++++++++++++++++ package.json | 15 + script.sh | 83 + 20 files changed, 2393 insertions(+), 13 deletions(-) create mode 100644 .env.sample create mode 100644 .github/workflows/main.yml create mode 100644 Dockerfile create mode 100644 Dockerfile-db create mode 100644 cypress.config.js create mode 100644 cypress/e2e/1-login.cy.js create mode 100644 cypress/e2e/2-version-info.cy.js create mode 100644 cypress/e2e/3-qso.cy.js create mode 100644 cypress/support/commands.js create mode 100644 cypress/support/e2e.js create mode 100644 docker-compose.yml create mode 100644 package-lock.json create mode 100644 package.json create mode 100755 script.sh diff --git a/.env.sample b/.env.sample new file mode 100644 index 000000000..2ff3bc361 --- /dev/null +++ b/.env.sample @@ -0,0 +1,9 @@ +MYSQL_ROOT_PASSWORD=rootpassword +MYSQL_DATABASE=cloudlog +MYSQL_USER=cloudlog +MYSQL_PASSWORD=cloudlogpassword +MYSQL_HOST=db +MYSQL_PORT=3306 +BASE_LOCATOR=IO91WM +WEBSITE_URL=http://localhost +DIRECTORY=/var/www/html \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..d107370a7 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,20 @@ +name: Cypress Tests +on: [pull_request] +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup .env + run: cp .env.sample .env + + - name: Build Docker services + run: docker-compose up -d + + - name: Install Cypress + run: npm install cypress + + - name: Run Cypress tests + run: npx cypress run diff --git a/.gitignore b/.gitignore index b46dc164f..0415a235b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,11 @@ /assets/qslcard/* /assets/sstvimages/* /assets/js/sections/custom.js +/cypress/screenshots +/node_modules .idea/* .DS_Store sync.sh *.p12 *.swp +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..812b536a3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +# Use the official image for PHP and Apache +FROM php:7.4-apache + +# Set the working directory to /var/www/html +WORKDIR /var/www/html + +# Install system dependencies, including git and libxml2 +RUN apt-get update && apt-get install -y \ + libcurl4-openssl-dev \ + libxml2-dev \ + libzip-dev \ + zlib1g-dev \ + libpng-dev \ + libonig-dev \ + default-mysql-client \ + curl \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* \ + && docker-php-ext-install pdo_mysql \ + && docker-php-ext-install mysqli \ + && docker-php-ext-install gd \ + && docker-php-ext-install mbstring \ + && docker-php-ext-install zip \ + && docker-php-ext-install xml \ + && a2enmod rewrite + +# # Copy .env, config.php, and database.php into the docker image +# COPY .env ./ +# COPY install/config/config.php install/config/ +# COPY install/config/database.php install/config/ + +# # Add a script that reads the .env file and replaces the variables in the config.php and database.php files +# ADD script.sh ./ +# RUN chmod +x script.sh + +# # Run the script at build time +# RUN ./script.sh + +# # Create the application/config directory +# RUN mkdir -p application/config + + +# Expose port 80 +EXPOSE 80 \ No newline at end of file diff --git a/Dockerfile-db b/Dockerfile-db new file mode 100644 index 000000000..ac550b76a --- /dev/null +++ b/Dockerfile-db @@ -0,0 +1,8 @@ +# Dockerfile-db +FROM mariadb:latest + +# Add the install.sql file to the docker image +ADD install/assets/install.sql /docker-entrypoint-initdb.d + +# Expose port 3306 +EXPOSE 3306 \ No newline at end of file diff --git a/README.md b/README.md index 668708944..d5cb02a4b 100644 --- a/README.md +++ b/README.md @@ -11,24 +11,58 @@ Core Contributors: 2M0SQL ([@magicbug](https://github.com/magicbug)), LA8AJA ([@ Website: [http://www.cloudlog.co.uk](http://www.cloudlog.co.uk) ## Requirements -* Linux based Operating System -* Apache (Nginx should work) -* PHP Version 7.4 (PHP 8.2 works) -* MySQL (MySQL 5.7 or higher) + +- Linux based Operating System +- Apache (Nginx should work) +- PHP Version 7.4 (PHP 8.2 works) +- MySQL (MySQL 5.7 or higher) Notes -* If you want to log microwave QSOs you will need to use a 64bit operating system. -* We do not provide Docker support, however you are free to use it if you wish but we will not handle support. + +- If you want to log microwave QSOs you will need to use a 64bit operating system. +- We do not provide Docker support, however you are free to use it if you wish but we will not handle support. ## Setup Installation information can be found on the [wiki](https://github.com/magicbug/Cloudlog/wiki). +# Docker Development Environment + +This guide provides instructions for setting up a local development environment using Docker and Docker Compose. Please note that this setup is not recommended for production use. + +## Prerequisites + +Before you begin, you need to install Docker and Docker Compose. You can download them using the following links: + +- [Docker](https://docs.docker.com/get-docker/) +- [Docker Compose](https://docs.docker.com/compose/install/) + +## Configuration + +1. Copy the `.env.sample` file to `.env`: + + ```bash + cp .env.sample .env + ``` + +2. Open the `.env` file and update the values to match your setup. The values from the `.env` file will be used to populate the database connection details on the install page. You should not need to change these unless your setup requires different values. + + **Note:** Docker Compose creates a network for your application, and each service (container) in the Docker Compose file can reach each other via the service name. This is why the `DB_HOST` value in the `.env` file and on the install page should match the service name of the database in the `docker-compose.yml` file. For example, if the database service in `docker-compose.yml` is defined as `db`, then `DB_HOST` should be set as 'db'. This allows the application to communicate with the database service on its internal docker network. + +## Starting the Development Environment + +To start the development environment, run the following command in your terminal: + +```bash +docker-compose up +``` + ## Support Cloudlog has two support systems for code issues use Github issues, however if you have general issues with setting up your server please use our general discussion forum [https://github.com/magicbug/Cloudlog/discussions](https://github.com/magicbug/Cloudlog/discussions). ## Security Vulnerabilities + If you discover a security vulnerability within Cloudlog, please send an e-mail to Peter Goodhall, 2M0SQL via [peter@magicbug.co.uk](mailto:peter@magicbug.co.uk). All security vulnerabilities will be promptly addressed. ## Want Cloudlog Hosting? @@ -53,4 +87,4 @@ Cloudlog is supported by Patreon and donations via PayPal, thanks to the followi Paul (M0TZO), Tim (G4VXE), Paul (N8HM), Michelle (W5NYV), Mitchell (AD0HJ), Dan (M0TCB), Martin (DK3ML), Juan Carlos (EA5WA), Iain (M0PCB), Charlie (GM1TGY), Ondrej (OK1CDJ), Trystan (G0KAY), Oliver (DL6KBG), Volkmar Schirmer, Jordan (M0PIR), Thomas Ziegler, Mathis (DB9MAT), Ken (VE3HLS), Tyler (WL7T), Jeremy Taylor, Ben Kuhn, Eric Thresher, Michael Cullen, Juuso (OH1JW), Anthony Castiglia, Fernando Ramirez-Ferrer, Robert Dixon, Mark Percival, Julia (KV1V), Timo Tomasini, Ant (NU1U), Christopher Williams, Danny Barnes, Vic, Tom (M0LTE), smurphboy, Lars (SM0TGU), Theo (PD9DP), Stefan (SM0RGM). Peter (G0ABI), Lou (KI5FTY), Michael (DG3NAB), Dragan (4O4A), minorsecond, Emily (W7AYQ), Steve (M0SKM), Rob (M0VFC), Doug (WA6L), Petr (OK1PKR), Fabian (HB9HIL), Daniel (OK2VLK), John (M5JFS). -If you'd like to donate to Cloudlog to help allow @magicbug spend less time doing commercial work and more time coding Cloudlog then you can donate via [PayPal](https://paypal.me/PGoodhall), [Github Sponsor](https://github.com/sponsors/magicbug) or become a [Patreon](https://www.patreon.com/2m0sql) +If you'd like to donate to Cloudlog to help allow @magicbug spend less time doing commercial work and more time coding Cloudlog then you can donate via [PayPal](https://paypal.me/PGoodhall), [Github Sponsor](https://github.com/sponsors/magicbug) or become a [Patreon](https://www.patreon.com/2m0sql) diff --git a/application/controllers/User_options.php b/application/controllers/User_options.php index d3a823e7d..431b20de2 100755 --- a/application/controllers/User_options.php +++ b/application/controllers/User_options.php @@ -59,6 +59,10 @@ public function get_map_custom() { echo json_encode($jsonout); } + public function enableVersionDialog() { + $this->user_options_model->set_option('version_dialog', 'confirmed', array('boolean' => 'false')); + } + public function dismissVersionDialog() { $this->user_options_model->set_option('version_dialog', 'confirmed', array('boolean' => 'true')); } diff --git a/application/views/view_log/partial/log.php b/application/views/view_log/partial/log.php index cc3c935f2..2d9c46cfa 100644 --- a/application/views/view_log/partial/log.php +++ b/application/views/view_log/partial/log.php @@ -153,7 +153,7 @@ - + diff --git a/application/views/view_log/qso.php b/application/views/view_log/qso.php index 2a0f3d63e..daeef76da 100644 --- a/application/views/view_log/qso.php +++ b/application/views/view_log/qso.php @@ -422,7 +422,7 @@ config->item('use_auth') && ($this->session->userdata('user_type') >= 2)) || $this->config->item('use_auth') === FALSE) { ?>
-

+

diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 000000000..f21033377 --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,11 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + projectId: 'gm8wco', + e2e: { + baseUrl: "http://localhost/", + setupNodeEvents(on, config) { + // implement node event listeners here + }, + }, +}); diff --git a/cypress/e2e/1-login.cy.js b/cypress/e2e/1-login.cy.js new file mode 100644 index 000000000..a7a849b25 --- /dev/null +++ b/cypress/e2e/1-login.cy.js @@ -0,0 +1,22 @@ +describe("Login Test", () => { + it("Should log in successfully", () => { + // Define the username and password + const username = "m0abc"; + const password = "demo"; + + // Visit the login page + cy.visit("/index.php/user/login"); + + // Type the username and password into the input fields + cy.get('input[name="user_name"]').type(username); + cy.get('input[name="user_password"]').type(password); + + // Click the login button + cy.get('button[type="submit"]').click(); + + // Check if the login was successful + // This could be checking/ for a URL change, looking for a log out button, etc. + cy.url().should("include", "/dashboard"); + cy.contains("Logout"); + }); +}); diff --git a/cypress/e2e/2-version-info.cy.js b/cypress/e2e/2-version-info.cy.js new file mode 100644 index 000000000..e91b01873 --- /dev/null +++ b/cypress/e2e/2-version-info.cy.js @@ -0,0 +1,46 @@ +describe("Version Info Modal", () => { + beforeEach(() => { + cy.login(); + cy.request( + "POST", + "http://localhost/index.php/user_options/enableVersionDialog" + ).wait(1000); + }); + + it("should open after login", () => { + // check if the modal is visible + cy.get(".modal-title").contains("Version Info").should("be.visible"); + }); + + it("should close after clicking 'Close' button", () => { + // check if the modal is visible + cy.get(".modal-title").contains("Version Info").should("be.visible"); + // click the 'Close' button + cy.get("button") + .contains("Close") + .should("be.visible") + .wait(500) + .click(); + + // check if the modal is not visible + cy.get(".modal-title") + .contains("Version Info") + .should("not.be.visible"); + }); + + it("should not show again after clicking 'Don't show again' button", () => { + // check if the modal is visible + cy.get(".modal-title").contains("Version Info").should("be.visible"); + // click the 'Close' button + cy.get("button") + .contains("Don't show again") + .should("be.visible") + .wait(500) + .click(); + + // check if the modal is not visible + cy.get(".modal-title") + .contains("Version Info") + .should("not.be.visible"); + }); +}); diff --git a/cypress/e2e/3-qso.cy.js b/cypress/e2e/3-qso.cy.js new file mode 100644 index 000000000..f3d54852e --- /dev/null +++ b/cypress/e2e/3-qso.cy.js @@ -0,0 +1,47 @@ +// describe("Post QSO Input Form", () => { +// beforeEach(() => { +// cy.login(); +// }); + +// it("Submits a QSO", () => { +// cy.visit("index.php/qso?manual=1"); + +// cy.get('select[name="mode"]').select("USB"); +// cy.get('select[name="band"]').select("20m"); +// cy.get('#qso_input input[name="callsign"]').first().type("KS3CKC"); + +// // Submit the QSO +// cy.get("#qso_input").submit(); + +// // Check if the QSO was added to the log +// cy.visit("index.php/dashboard"); + +// cy.get("table > tbody > tr:first").within(() => { +// cy.get("td").eq(2).should("contain", "KS3CKC"); +// cy.get("td").eq(3).should("contain", "USB"); +// cy.get("td").eq(6).should("contain", "20m"); +// }); +// }); + +// it("Delete a QSO", () => { +// cy.visit("index.php/dashboard"); + +// // Click the link in the first row of the table to open the modal +// cy.get("table > tbody > tr:first").within(() => { +// cy.get("a").first().click(); +// }); + +// // Click the "Edit QSO" button +// cy.get("a").contains("Edit QSO").should("be.visible").click(); + +// // Click the delete button +// cy.get("a") +// .contains("Delete QSO") +// .scrollIntoView() +// .should("be.visible") +// .click(); + +// // Click the confirm delete button +// cy.get("button").contains("OK").should("be.visible").click(); +// }); +// }); diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..80e96b913 --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,8 @@ +Cypress.Commands.add("login", () => { + const username = "m0abc"; + const password = "demo"; + cy.visit("/index.php/user/login"); + cy.get('input[name="user_name"]').type(username); + cy.get('input[name="user_password"]').type(password); + cy.get('button[type="submit"]').click(); +}); diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 000000000..0e7290a13 --- /dev/null +++ b/cypress/support/e2e.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..b6a3c29dc --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: "3.8" + +services: + web: + build: . + env_file: + - .env + ports: + - "80:80" + volumes: + - ./:/var/www/html:rw + command: ["./script.sh"] + depends_on: + - db + + db: + build: + context: . + dockerfile: Dockerfile-db + env_file: + - .env + volumes: + - db_data:/var/lib/mysql +volumes: + db_data: {} diff --git a/install/index.php b/install/index.php index 9524e520a..20bed23ef 100644 --- a/install/index.php +++ b/install/index.php @@ -148,10 +148,10 @@ function delDir($dir) {
Database settings - - - - + + + +
diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..fc2f192a5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1981 @@ +{ + "name": "cloudlog", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cloudlog", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "cypress": "^13.7.2" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.10.4", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@types/node": { + "version": "20.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz", + "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==", + "dev": true, + "optional": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.4.tgz", + "integrity": "sha512-Lm3L0p+/npIQWNIiyF/nAn7T5dnOwR3xNTHXYEBFBFVPXzCVNZ5lqEC/1eo/EVfpDsQ1I+TX4ORPQgp+UI0CRw==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cypress": { + "version": "13.7.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.2.tgz", + "integrity": "sha512-FF5hFI5wlRIHY8urLZjJjj/YvfCBrRpglbZCLr/cYcL9MdDe0+5usa8kTIrDHthlEc9lwihbkb5dmwqBDNS2yw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@cypress/request": "^3.0.0", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.1", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "dev": true + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", + "dev": true + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", + "dev": true, + "dependencies": { + "throttleit": "^1.0.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "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==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/throttleit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "optional": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..a3dfc75cd --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "cloudlog", + "version": "1.0.0", + "description": "> Important: Only accepting PRs on the \"dev\" branch.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "cypress": "^13.7.2" + } +} diff --git a/script.sh b/script.sh new file mode 100755 index 000000000..c1447f8fa --- /dev/null +++ b/script.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# Define the file path for .env and the file to modify +if [ -f "./.env" ]; then + ENV_FILE="./.env" +else + ENV_FILE="./.env.sample" +fi +CONFIG_FILE="install/config/config.php" +DATABASE_FILE="install/config/database.php" +DEST_DIR="application/config" + +# Check if .env file exists +if [ ! -f "$ENV_FILE" ]; then + echo ".env file not found!" + exit 1 +fi + +# Read the .env file +source $ENV_FILE + +# Check if MYSQL_DATABASE is set +if [ -z "${MYSQL_DATABASE}" ]; then + echo "MYSQL_DATABASE is not set in .env file!" + exit 1 +fi +# Check if MYSQL_USER is set +if [ -z "${MYSQL_USER}" ]; then + echo "MYSQL_USER is not set in .env file!" + exit 1 +fi +# Check if MYSQL_PASSWORD is set +if [ -z "${MYSQL_PASSWORD}" ]; then + echo "MYSQL_PASSWORD is not set in .env file!" + exit 1 +fi +# Check if MYSQL_HOST is set +if [ -z "${MYSQL_HOST}" ]; then + echo "MYSQL_HOST is not set in .env file!" + exit 1 +fi +# Check if BASE_LOCATOR is set +if [ -z "${BASE_LOCATOR}" ]; then + echo "BASE_LOCATOR is not set in .env file!" + exit 1 +fi +# Check if WEBSITE_URL is set +if [ -z "${WEBSITE_URL}" ]; then + echo "WEBSITE_URL is not set in .env file!" + exit 1 +fi +# Check if DIRECTORY is set +if [ -z "${DIRECTORY}" ]; then + echo "DIRECTORY is not set in .env file!" + exit 1 +fi + +# Check if destination directory exists, if not create it +if [ ! -d "$DEST_DIR" ]; then + mkdir -p $DEST_DIR +fi + + +# Use sed with a different delimiter (`|`) to avoid conflicts with special characters +sed -i "s|%DATABASE%|${MYSQL_DATABASE}|g" $DATABASE_FILE +sed -i "s|%USERNAME%|${MYSQL_USER}|g" $DATABASE_FILE +sed -i "s|%PASSWORD%|${MYSQL_PASSWORD}|g" $DATABASE_FILE +sed -i "s|%HOSTNAME%|${MYSQL_HOST}|g" $DATABASE_FILE +sed -i "s|%baselocator%|${BASE_LOCATOR}|g" $CONFIG_FILE +sed -i "s|%websiteurl%|${WEBSITE_URL}|g" $CONFIG_FILE +sed -i "s|%directory%|${DIRECTORY}|g" $CONFIG_FILE + +# Move the files to the destination directory +mv $CONFIG_FILE $DEST_DIR +mv $DATABASE_FILE $DEST_DIR + +# Delete the /install directory +rm -rf /install + +echo "Replacement complete." + +# Start Apache in the foreground +exec apache2-foreground \ No newline at end of file From a0a12c776c9386bc8fe4d245ef6214c58eb3011a Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 14:04:11 -0500 Subject: [PATCH 02/37] update test nad a few other minor updates --- .gitignore | 2 +- Dockerfile | 16 ---------------- cypress/e2e/2-version-info.cy.js | 30 +++++++++++++++++++++++------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 0415a235b..1654f5660 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ /assets/sstvimages/* /assets/js/sections/custom.js /cypress/screenshots -/node_modules +/node_modules/ .idea/* .DS_Store sync.sh diff --git a/Dockerfile b/Dockerfile index 812b536a3..cfaf7523d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,21 +24,5 @@ RUN apt-get update && apt-get install -y \ && docker-php-ext-install xml \ && a2enmod rewrite -# # Copy .env, config.php, and database.php into the docker image -# COPY .env ./ -# COPY install/config/config.php install/config/ -# COPY install/config/database.php install/config/ - -# # Add a script that reads the .env file and replaces the variables in the config.php and database.php files -# ADD script.sh ./ -# RUN chmod +x script.sh - -# # Run the script at build time -# RUN ./script.sh - -# # Create the application/config directory -# RUN mkdir -p application/config - - # Expose port 80 EXPOSE 80 \ No newline at end of file diff --git a/cypress/e2e/2-version-info.cy.js b/cypress/e2e/2-version-info.cy.js index e91b01873..ed3f2f747 100644 --- a/cypress/e2e/2-version-info.cy.js +++ b/cypress/e2e/2-version-info.cy.js @@ -1,18 +1,23 @@ describe("Version Info Modal", () => { beforeEach(() => { cy.login(); - cy.request( - "POST", - "http://localhost/index.php/user_options/enableVersionDialog" - ).wait(1000); }); it("should open after login", () => { - // check if the modal is visible + // Make sure the dialog is enabled + cy.request({ + method: "POST", + url: "http://localhost/index.php/user_options/enableVersionDialog", + }).wait(1000); cy.get(".modal-title").contains("Version Info").should("be.visible"); }); it("should close after clicking 'Close' button", () => { + // Make sure the dialog is enabled + cy.request({ + method: "POST", + url: "http://localhost/index.php/user_options/enableVersionDialog", + }).wait(1000); // check if the modal is visible cy.get(".modal-title").contains("Version Info").should("be.visible"); // click the 'Close' button @@ -28,10 +33,16 @@ describe("Version Info Modal", () => { .should("not.be.visible"); }); - it("should not show again after clicking 'Don't show again' button", () => { + it("should close after clicking 'Don't show again' button", () => { + // Make sure the dialog is enabled + cy.request({ + method: "POST", + url: "http://localhost/index.php/user_options/enableVersionDialog", + }).wait(1000); + // check if the modal is visible cy.get(".modal-title").contains("Version Info").should("be.visible"); - // click the 'Close' button + // click the "Don't show again" button cy.get("button") .contains("Don't show again") .should("be.visible") @@ -43,4 +54,9 @@ describe("Version Info Modal", () => { .contains("Version Info") .should("not.be.visible"); }); + + it("should not show the version info dialog after click 'Dont show again' button", () => { + // check if the modal is not visible + cy.get(".modal-title").should("not.exist"); + }); }); From 0473a3c6214c911b7b62e1be6c56f8d3feaff506 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 14:09:45 -0500 Subject: [PATCH 03/37] update main.yml -> cypress-tests.yml --- .github/workflows/{main.yml => cypress-tests.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{main.yml => cypress-tests.yml} (95%) diff --git a/.github/workflows/main.yml b/.github/workflows/cypress-tests.yml similarity index 95% rename from .github/workflows/main.yml rename to .github/workflows/cypress-tests.yml index d107370a7..00c59dbf0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/cypress-tests.yml @@ -1,7 +1,7 @@ name: Cypress Tests on: [pull_request] jobs: - test: + cypress-e2e-tests: runs-on: ubuntu-latest steps: - name: Checkout code From bfb39c0b1d96becccdfd2262fa3cefdbbf2e97aa Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 14:16:55 -0500 Subject: [PATCH 04/37] undo qso changes, will address those later --- application/views/view_log/qso.php | 4 +-- cypress/e2e/3-qso.cy.js | 47 ------------------------------ 2 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 cypress/e2e/3-qso.cy.js diff --git a/application/views/view_log/qso.php b/application/views/view_log/qso.php index daeef76da..66152f81f 100644 --- a/application/views/view_log/qso.php +++ b/application/views/view_log/qso.php @@ -422,7 +422,7 @@ config->item('use_auth') && ($this->session->userdata('user_type') >= 2)) || $this->config->item('use_auth') === FALSE) { ?>
-

+

@@ -764,4 +764,4 @@ - + \ No newline at end of file diff --git a/cypress/e2e/3-qso.cy.js b/cypress/e2e/3-qso.cy.js deleted file mode 100644 index f3d54852e..000000000 --- a/cypress/e2e/3-qso.cy.js +++ /dev/null @@ -1,47 +0,0 @@ -// describe("Post QSO Input Form", () => { -// beforeEach(() => { -// cy.login(); -// }); - -// it("Submits a QSO", () => { -// cy.visit("index.php/qso?manual=1"); - -// cy.get('select[name="mode"]').select("USB"); -// cy.get('select[name="band"]').select("20m"); -// cy.get('#qso_input input[name="callsign"]').first().type("KS3CKC"); - -// // Submit the QSO -// cy.get("#qso_input").submit(); - -// // Check if the QSO was added to the log -// cy.visit("index.php/dashboard"); - -// cy.get("table > tbody > tr:first").within(() => { -// cy.get("td").eq(2).should("contain", "KS3CKC"); -// cy.get("td").eq(3).should("contain", "USB"); -// cy.get("td").eq(6).should("contain", "20m"); -// }); -// }); - -// it("Delete a QSO", () => { -// cy.visit("index.php/dashboard"); - -// // Click the link in the first row of the table to open the modal -// cy.get("table > tbody > tr:first").within(() => { -// cy.get("a").first().click(); -// }); - -// // Click the "Edit QSO" button -// cy.get("a").contains("Edit QSO").should("be.visible").click(); - -// // Click the delete button -// cy.get("a") -// .contains("Delete QSO") -// .scrollIntoView() -// .should("be.visible") -// .click(); - -// // Click the confirm delete button -// cy.get("button").contains("OK").should("be.visible").click(); -// }); -// }); From f28bc904ad05690552eeba8dfc44404eb81ddc61 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 14:20:39 -0500 Subject: [PATCH 05/37] undo one more minor change that was related to qso testing, will address it later --- application/views/view_log/partial/log.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/views/view_log/partial/log.php b/application/views/view_log/partial/log.php index 2d9c46cfa..abaec22b8 100644 --- a/application/views/view_log/partial/log.php +++ b/application/views/view_log/partial/log.php @@ -153,7 +153,7 @@ - + @@ -191,4 +191,4 @@ - + \ No newline at end of file From 0e7232a50c450773a53d261595d72cdadb2d2bd3 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 14:33:17 -0500 Subject: [PATCH 06/37] add notes about running tests locally to readme --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index d5cb02a4b..82ba8a9c5 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,47 @@ To start the development environment, run the following command in your terminal docker-compose up ``` +# Running Cypress Tests Locally + +Follow these steps to run the Cypress tests locally on your machine: + +1. **Clone the repository** + + If you haven't already, clone the repository to your local machine + +2. **Setup .env file** + + Copy the sample `.env` file and adjust it to your local environment: + + ```bash + cd your-repo + cp .env.sample .env + ``` + +3. **Build Docker services** + + Build and start the Docker services: + + ```bash + docker-compose up -d + ``` + +4. **Install Cypress** + + Navigate into the project directory and install Cypress: + + ```bash + npm install cypress + ``` + +5. **Run the Cypress tests** + + After the installation is complete, you can run the Cypress tests: + + ```bash + npx cypress run + ``` + ## Support Cloudlog has two support systems for code issues use Github issues, however if you have general issues with setting up your server please use our general discussion forum [https://github.com/magicbug/Cloudlog/discussions](https://github.com/magicbug/Cloudlog/discussions). From e1f75906eedbe7bdfa0bc22e7febd9203219269d Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 15:58:55 -0500 Subject: [PATCH 07/37] add tests for new account alerts --- cypress/e2e/3-new-account-notifications.cy.js | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 cypress/e2e/3-new-account-notifications.cy.js diff --git a/cypress/e2e/3-new-account-notifications.cy.js b/cypress/e2e/3-new-account-notifications.cy.js new file mode 100644 index 000000000..1dba6566b --- /dev/null +++ b/cypress/e2e/3-new-account-notifications.cy.js @@ -0,0 +1,91 @@ +// Test suite for new account notifications within the application +describe("New account notifications", () => { + // Before each test, perform login operation. Assumes cy.login() is a custom command. + beforeEach(() => { + cy.login(); + }); + + // Notification messages expected to be seen by new accounts + const locationsNotificationMessage = + "You have no station locations. Go here to create it!"; + const logbookNotificationMessage = + "You have no station logbook. Go here to create it!"; + const activeStationNotificationMessage = + "Attention: you need to set an active station location."; + const noQSONotificationMessage = + "You have made no QSOs today; time to turn on the radio!"; + + // Test to verify the locations notification message and its link + it(`should show a "${locationsNotificationMessage}" notification with a valid link to create it`, () => { + // Verify notification visibility and class for urgency + cy.get("body") + .contains(locationsNotificationMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + + // Validate the hyperlink's destination within the notification + cy.contains(locationsNotificationMessage).within(() => { + cy.get("a") + .contains("here") + .should("have.attr", "href") + .and("equal", "http://localhost/index.php/station"); + }); + }); + + // Test navigation to the station creation page via the notification link + it("should navigate to the station creation page after clicking the link in the notification", () => { + // Trigger click on the link within the notification message + cy.contains(locationsNotificationMessage).within(() => { + cy.get("a").contains("here").click(); + }); + + // Assert the correct page has been loaded by checking the URL + cy.url().should("include", "/station"); + }); + + // Test to verify the logbook notification message and its link + it(`should show a "${logbookNotificationMessage}" notification with a valid link to create it`, () => { + // Verify notification visibility and class for urgency + cy.get("body") + .contains(logbookNotificationMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + + // Validate the hyperlink's destination within the notification + cy.contains(logbookNotificationMessage).within(() => { + cy.get("a") + .contains("here") + .should("have.attr", "href") + .and("equal", "http://localhost/index.php/logbooks"); + }); + }); + + // Test navigation to the logbook creation page via the notification link + it("should navigate to the logbook creation page after clicking the link in the notification", () => { + // Trigger click on the link within the notification message + cy.contains(logbookNotificationMessage).within(() => { + cy.get("a").contains("here").click(); + }); + + // Assert the correct page has been loaded by checking the URL + cy.url().should("include", "/logbooks"); + }); + + // Test to verify the active station notification is properly displayed + it(`should display an "${activeStationNotificationMessage}" notification`, () => { + // Verify notification visibility and class for urgency + cy.get("body") + .contains(activeStationNotificationMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + }); + + // Test to verify the no QSO notification is properly displayed + it(`should display a "${noQSONotificationMessage}" notification`, () => { + // Verify notification visibility and class for importance + cy.get("body") + .contains(noQSONotificationMessage) + .should("be.visible") + .and("have.class", "alert-warning"); + }); +}); From 8ade6979dfd85d80d8477bcecf9bf0396844235f Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 16:09:22 -0500 Subject: [PATCH 08/37] more login page tests --- cypress/e2e/1-login.cy.js | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/cypress/e2e/1-login.cy.js b/cypress/e2e/1-login.cy.js index a7a849b25..61515bd97 100644 --- a/cypress/e2e/1-login.cy.js +++ b/cypress/e2e/1-login.cy.js @@ -19,4 +19,67 @@ describe("Login Test", () => { cy.url().should("include", "/dashboard"); cy.contains("Logout"); }); + + it("Should display an error message on failed login", () => { + // Define the username and password + const username = "m0abc"; + const password = "wrongpassword"; + + // Visit the login page + cy.visit("/index.php/user/login"); + + // Type the username and password into the input fields + cy.get('input[name="user_name"]').type(username); + cy.get('input[name="user_password"]').type(password); + + // Click the login button + cy.get('button[type="submit"]').click(); + + // Check if the login was successful + // This could be checking/ for a URL change, looking for a log out button, etc. + cy.url().should("include", "/login"); + + cy.get("body") + .contains("Incorrect username or password!") + .should("be.visible") + .and("have.class", "alert-danger"); + }); + + it("Should display an error message on empty fields", () => { + // Visit the login page + cy.visit("/index.php/user/login"); + + // Click the login button + cy.get('button[type="submit"]').click(); + + // Check if the login was successful + // This could be checking/ for a URL change, looking for a log out button, etc. + cy.url().should("include", "/login"); + + cy.get("body") + .contains(`The "Username" field is required.`) + .should("be.visible") + .parent() + .and("have.class", "alert-danger"); + + cy.get("body") + .contains(`The "Password" field is required.`) + .should("be.visible") + .parent() + .and("have.class", "alert-danger"); + }); + + it("Should display and open the forgot password page", () => { + // Visit the login page + cy.visit("/index.php/user/login"); + + // Click the "Forgot Password?" link + cy.get("a") + .contains("Forgot your password?") + .should("be.visible") + .click(); + + // Check if the correct page has been loaded by checking the URL + cy.url().should("include", "/forgot_password"); + }); }); From 3dd728d25105cd0d96791a78b9a1d70e63a504a7 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 16:18:45 -0500 Subject: [PATCH 09/37] change notifications to alerts and only number login/verify since it sets a global flag --- cypress/e2e/3-new-account-notifications.cy.js | 91 ------------------- cypress/e2e/new-account-alerts.cy.js | 91 +++++++++++++++++++ 2 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 cypress/e2e/3-new-account-notifications.cy.js create mode 100644 cypress/e2e/new-account-alerts.cy.js diff --git a/cypress/e2e/3-new-account-notifications.cy.js b/cypress/e2e/3-new-account-notifications.cy.js deleted file mode 100644 index 1dba6566b..000000000 --- a/cypress/e2e/3-new-account-notifications.cy.js +++ /dev/null @@ -1,91 +0,0 @@ -// Test suite for new account notifications within the application -describe("New account notifications", () => { - // Before each test, perform login operation. Assumes cy.login() is a custom command. - beforeEach(() => { - cy.login(); - }); - - // Notification messages expected to be seen by new accounts - const locationsNotificationMessage = - "You have no station locations. Go here to create it!"; - const logbookNotificationMessage = - "You have no station logbook. Go here to create it!"; - const activeStationNotificationMessage = - "Attention: you need to set an active station location."; - const noQSONotificationMessage = - "You have made no QSOs today; time to turn on the radio!"; - - // Test to verify the locations notification message and its link - it(`should show a "${locationsNotificationMessage}" notification with a valid link to create it`, () => { - // Verify notification visibility and class for urgency - cy.get("body") - .contains(locationsNotificationMessage) - .should("be.visible") - .and("have.class", "alert-danger"); - - // Validate the hyperlink's destination within the notification - cy.contains(locationsNotificationMessage).within(() => { - cy.get("a") - .contains("here") - .should("have.attr", "href") - .and("equal", "http://localhost/index.php/station"); - }); - }); - - // Test navigation to the station creation page via the notification link - it("should navigate to the station creation page after clicking the link in the notification", () => { - // Trigger click on the link within the notification message - cy.contains(locationsNotificationMessage).within(() => { - cy.get("a").contains("here").click(); - }); - - // Assert the correct page has been loaded by checking the URL - cy.url().should("include", "/station"); - }); - - // Test to verify the logbook notification message and its link - it(`should show a "${logbookNotificationMessage}" notification with a valid link to create it`, () => { - // Verify notification visibility and class for urgency - cy.get("body") - .contains(logbookNotificationMessage) - .should("be.visible") - .and("have.class", "alert-danger"); - - // Validate the hyperlink's destination within the notification - cy.contains(logbookNotificationMessage).within(() => { - cy.get("a") - .contains("here") - .should("have.attr", "href") - .and("equal", "http://localhost/index.php/logbooks"); - }); - }); - - // Test navigation to the logbook creation page via the notification link - it("should navigate to the logbook creation page after clicking the link in the notification", () => { - // Trigger click on the link within the notification message - cy.contains(logbookNotificationMessage).within(() => { - cy.get("a").contains("here").click(); - }); - - // Assert the correct page has been loaded by checking the URL - cy.url().should("include", "/logbooks"); - }); - - // Test to verify the active station notification is properly displayed - it(`should display an "${activeStationNotificationMessage}" notification`, () => { - // Verify notification visibility and class for urgency - cy.get("body") - .contains(activeStationNotificationMessage) - .should("be.visible") - .and("have.class", "alert-danger"); - }); - - // Test to verify the no QSO notification is properly displayed - it(`should display a "${noQSONotificationMessage}" notification`, () => { - // Verify notification visibility and class for importance - cy.get("body") - .contains(noQSONotificationMessage) - .should("be.visible") - .and("have.class", "alert-warning"); - }); -}); diff --git a/cypress/e2e/new-account-alerts.cy.js b/cypress/e2e/new-account-alerts.cy.js new file mode 100644 index 000000000..61f52ef90 --- /dev/null +++ b/cypress/e2e/new-account-alerts.cy.js @@ -0,0 +1,91 @@ +// Test suite for new account alerts within the application +describe("New account alerts", () => { + // Before each test, perform login operation. Assumes cy.login() is a custom command. + beforeEach(() => { + cy.login(); + }); + + // Alert messages expected to be seen by brand new accounts + const locationsAlertMessage = + "You have no station locations. Go here to create it!"; + const logbookAlertMessage = + "You have no station logbook. Go here to create it!"; + const activeStationAlertMessage = + "Attention: you need to set an active station location."; + const noQSOAlertMessage = + "You have made no QSOs today; time to turn on the radio!"; + + // Test to verify the locations alert message and its link + it(`should show a "${locationsAlertMessage}" alert with a valid link to create it`, () => { + // Verify alert visibility and class for urgency + cy.get("body") + .contains(locationsAlertMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + + // Validate the hyperlink's destination within the alert + cy.contains(locationsAlertMessage).within(() => { + cy.get("a") + .contains("here") + .should("have.attr", "href") + .and("equal", "http://localhost/index.php/station"); + }); + }); + + // Test navigation to the station creation page via the alert link + it("should navigate to the station creation page after clicking the link in the alert", () => { + // Trigger click on the link within the alert message + cy.contains(locationsAlertMessage).within(() => { + cy.get("a").contains("here").click(); + }); + + // Assert the correct page has been loaded by checking the URL + cy.url().should("include", "/station"); + }); + + // Test to verify the logbook alert message and its link + it(`should show a "${logbookAlertMessage}" alert with a valid link to create it`, () => { + // Verify alert visibility and class for urgency + cy.get("body") + .contains(logbookAlertMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + + // Validate the hyperlink's destination within the alert + cy.contains(logbookAlertMessage).within(() => { + cy.get("a") + .contains("here") + .should("have.attr", "href") + .and("equal", "http://localhost/index.php/logbooks"); + }); + }); + + // Test navigation to the logbook creation page via the alert link + it("should navigate to the logbook creation page after clicking the link in the alert", () => { + // Trigger click on the link within the alert message + cy.contains(logbookAlertMessage).within(() => { + cy.get("a").contains("here").click(); + }); + + // Assert the correct page has been loaded by checking the URL + cy.url().should("include", "/logbooks"); + }); + + // Test to verify the active station alert is properly displayed + it(`should display an "${activeStationAlertMessage}" alert`, () => { + // Verify alert visibility and class for urgency + cy.get("body") + .contains(activeStationAlertMessage) + .should("be.visible") + .and("have.class", "alert-danger"); + }); + + // Test to verify the no QSO alert is properly displayed + it(`should display a "${noQSOAlertMessage}" alert`, () => { + // Verify alert visibility and class for importance + cy.get("body") + .contains(noQSOAlertMessage) + .should("be.visible") + .and("have.class", "alert-warning"); + }); +}); From 45fc6b96bea84277ac42e65fc7223588baa2d180 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 17:21:40 -0500 Subject: [PATCH 10/37] station-location create added --- ...lerts.cy.js => 3-new-account-alerts.cy.js} | 0 cypress/e2e/4-station-locations.cy.js | 69 +++++++++++++++++++ 2 files changed, 69 insertions(+) rename cypress/e2e/{new-account-alerts.cy.js => 3-new-account-alerts.cy.js} (100%) create mode 100644 cypress/e2e/4-station-locations.cy.js diff --git a/cypress/e2e/new-account-alerts.cy.js b/cypress/e2e/3-new-account-alerts.cy.js similarity index 100% rename from cypress/e2e/new-account-alerts.cy.js rename to cypress/e2e/3-new-account-alerts.cy.js diff --git a/cypress/e2e/4-station-locations.cy.js b/cypress/e2e/4-station-locations.cy.js new file mode 100644 index 000000000..1e3104fa5 --- /dev/null +++ b/cypress/e2e/4-station-locations.cy.js @@ -0,0 +1,69 @@ +describe("Create station location", () => { + beforeEach(() => { + cy.login(); + }); + + it("should load an empty list of station locations", () => { + cy.visit("/index.php/station"); + + // Check that the table is not present + cy.get("#station_locations_table").should("not.exist"); + }); + + it("should have a button to create a new station location", () => { + cy.visit("/index.php/station"); + + // Check that the button is present + cy.get("a") + .contains("Create a Station Location") + .should("exist") + .click(); + + cy.url().should("include", "/station/create"); + }); + + it("should create a new station location", () => { + cy.visit("/index.php/station/create"); + + // Define the station location name + const stationLocationName = "Test Station Location"; + const stationCallsign = "2M0SQL"; + const stationPower = "100"; + const stationDXCC = "United States Of America - K"; + const stationCity = "Olathe"; + const stationState = "Kansas"; + const stationCounty = "Johnson"; + const stationGridsquare = "EM28"; + const stationCQ = "4"; + const stationITU = "7"; + + // Type the station location name into the input field + cy.get('input[name="station_profile_name"]').type(stationLocationName); + cy.get('input[name="station_callsign"]').type(stationCallsign); + cy.get('input[name="station_power"]').type(stationPower); + cy.get('select[name="dxcc"]').select(stationDXCC); + cy.get('input[name="city"]').type(stationCity); + cy.get('select[name="station_state"]').select(stationState); + cy.get("#stationCntyInput-selectized") + .type(stationCounty, { force: true }) // force typing if the element isn't initially visible + .get(".selectize-dropdown-content > div") // get the dropdown content + .contains(stationCounty) // find the option containing the county name + .click(); // click to select the option + cy.get('input[name="gridsquare"]').type(stationGridsquare); + cy.get('select[name="station_cq"]').select(stationCQ); + cy.get('select[name="station_itu"]').select(stationITU); + + // Click the save button + cy.get('button[type="submit"]') + .contains("Create Station Location") + .click(); + + // Check if the station location was created successfully + cy.url().should("include", "/station"); + + // // Check if the station location is present in the table + cy.get("#station_locations_table") + .contains(stationLocationName) + .should("exist"); + }); +}); From 155537e99c3245495c506bf6f3acdd0d697c5d5b Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:18:48 -0500 Subject: [PATCH 11/37] add request to populate dxcc_entities --- script.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script.sh b/script.sh index c1447f8fa..0581b3a37 100755 --- a/script.sh +++ b/script.sh @@ -79,5 +79,8 @@ rm -rf /install echo "Replacement complete." +# Send a GET request to populate the dxcc_entities table +curl "${WEBSITE_URL}/index.php/update/dxcc_entities" + # Start Apache in the foreground exec apache2-foreground \ No newline at end of file From 3d5169bbdd5c21d5090697880cd67be5171cb59f Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:25:23 -0500 Subject: [PATCH 12/37] move request to the before on the station tests --- cypress/e2e/4-station-locations.cy.js | 6 ++++++ script.sh | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cypress/e2e/4-station-locations.cy.js b/cypress/e2e/4-station-locations.cy.js index 1e3104fa5..9f4496b2f 100644 --- a/cypress/e2e/4-station-locations.cy.js +++ b/cypress/e2e/4-station-locations.cy.js @@ -1,4 +1,10 @@ describe("Create station location", () => { + before(() => { + cy.request({ + method: "GET", + url: "/index.php/update/dxcc_entities", + }).wait(1000); + }); beforeEach(() => { cy.login(); }); diff --git a/script.sh b/script.sh index 0581b3a37..c1447f8fa 100755 --- a/script.sh +++ b/script.sh @@ -79,8 +79,5 @@ rm -rf /install echo "Replacement complete." -# Send a GET request to populate the dxcc_entities table -curl "${WEBSITE_URL}/index.php/update/dxcc_entities" - # Start Apache in the foreground exec apache2-foreground \ No newline at end of file From f65a8c1e125b7f96fbb5b47561ccee2daaf6ee1b Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:39:19 -0500 Subject: [PATCH 13/37] still trying to populate dxcc_entities for the station creation tests --- cypress/e2e/4-station-locations.cy.js | 6 ------ script.sh | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cypress/e2e/4-station-locations.cy.js b/cypress/e2e/4-station-locations.cy.js index 9f4496b2f..1e3104fa5 100644 --- a/cypress/e2e/4-station-locations.cy.js +++ b/cypress/e2e/4-station-locations.cy.js @@ -1,10 +1,4 @@ describe("Create station location", () => { - before(() => { - cy.request({ - method: "GET", - url: "/index.php/update/dxcc_entities", - }).wait(1000); - }); beforeEach(() => { cy.login(); }); diff --git a/script.sh b/script.sh index c1447f8fa..4282569b8 100755 --- a/script.sh +++ b/script.sh @@ -79,5 +79,7 @@ rm -rf /install echo "Replacement complete." +php /var/www/html/index.php update dxcc_entities + # Start Apache in the foreground exec apache2-foreground \ No newline at end of file From a361d593e52eb9fd9211f6c646e0b21c76949498 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:46:21 -0500 Subject: [PATCH 14/37] move it to github actions run step --- .github/workflows/cypress-tests.yml | 3 +++ script.sh | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 00c59dbf0..adf0b3ff1 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -13,6 +13,9 @@ jobs: - name: Build Docker services run: docker-compose up -d + - name: Populate dxcc_entities table + run: curl "http://localhost/index.php/update/dxcc_entities" + - name: Install Cypress run: npm install cypress diff --git a/script.sh b/script.sh index 4282569b8..c1447f8fa 100755 --- a/script.sh +++ b/script.sh @@ -79,7 +79,5 @@ rm -rf /install echo "Replacement complete." -php /var/www/html/index.php update dxcc_entities - # Start Apache in the foreground exec apache2-foreground \ No newline at end of file From 08d2ffaa3bf70f26a306ceead816d8bd41b04924 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:49:57 -0500 Subject: [PATCH 15/37] add a short delay to let web connect to db --- .github/workflows/cypress-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index adf0b3ff1..15dc4c0db 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -13,6 +13,9 @@ jobs: - name: Build Docker services run: docker-compose up -d + - name: Wait for services to start + run: sleep 10 + - name: Populate dxcc_entities table run: curl "http://localhost/index.php/update/dxcc_entities" From e0af386cc539e16344ce789615d66a793f2e6af4 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 19:58:37 -0500 Subject: [PATCH 16/37] add another request for dxcc --- .github/workflows/cypress-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 15dc4c0db..2cb67cebb 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -16,6 +16,9 @@ jobs: - name: Wait for services to start run: sleep 10 + - name: Populate dxcc_entities table + run: curl "http://localhost/index.php/update/dxcc" + - name: Populate dxcc_entities table run: curl "http://localhost/index.php/update/dxcc_entities" From ede0b201a5b4c75120a2498466222281fb449d03 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:04:08 -0500 Subject: [PATCH 17/37] attempt to add the permissions stuff to the script.sh before adding it to github actions --- script.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/script.sh b/script.sh index c1447f8fa..6512444cf 100755 --- a/script.sh +++ b/script.sh @@ -79,5 +79,24 @@ rm -rf /install echo "Replacement complete." +# Set Permissions +chown -R root:www-data /var/www/html/application/config/ +chown -R root:www-data /var/www/html/application/logs/ +chown -R root:www-data /var/www/html/assets/qslcard/ +chown -R root:www-data /var/www/html/backup/ +chown -R root:www-data /var/www/html/updates/ +chown -R root:www-data /var/www/html/uploads/ +chown -R root:www-data /var/www/html/images/eqsl_card_images/ +chown -R root:www-data /var/www/html/assets/json + +chmod -R g+rw /var/www/html/application/config/ +chmod -R g+rw /var/www/html/application/logs/ +chmod -R g+rw /var/www/html/assets/qslcard/ +chmod -R g+rw /var/www/html/backup/ +chmod -R g+rw /var/www/html/updates/ +chmod -R g+rw /var/www/html/uploads/ +chmod -R g+rw /var/www/html/images/eqsl_card_images/ +chmod -R g+rw /var/www/html/assets/json + # Start Apache in the foreground exec apache2-foreground \ No newline at end of file From 08c5e4420f85f7fa0dfddddac0cbaf11fd6b9a2f Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:08:43 -0500 Subject: [PATCH 18/37] testing if i need both dxcc calls --- .github/workflows/cypress-tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 2cb67cebb..92cc4d1a9 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -19,9 +19,6 @@ jobs: - name: Populate dxcc_entities table run: curl "http://localhost/index.php/update/dxcc" - - name: Populate dxcc_entities table - run: curl "http://localhost/index.php/update/dxcc_entities" - - name: Install Cypress run: npm install cypress From 485c21a1eb030ca337b503d52ff166a5ddec990f Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:16:12 -0500 Subject: [PATCH 19/37] attempting to add some caching and speed up the delay --- .github/workflows/cypress-tests.yml | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index 92cc4d1a9..f16d68c48 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -7,20 +7,39 @@ jobs: - name: Checkout code uses: actions/checkout@v2 + - name: Cache Cypress + uses: actions/cache@v2 + with: + path: ~/.cache/Cypress + key: cypress-${{ hashFiles('package-lock.json') }} + restore-keys: | + cypress- + + - name: Install Cypress + run: npm install cypress + + - name: Cache .env + uses: actions/cache@v2 + with: + path: .env + key: .env-${{ hashFiles('.env.sample') }} + restore-keys: | + .env- + - name: Setup .env - run: cp .env.sample .env + run: | + if [ ! -f .env ]; then + cp .env.sample .env + fi - name: Build Docker services run: docker-compose up -d - name: Wait for services to start - run: sleep 10 + run: sleep 3 - name: Populate dxcc_entities table run: curl "http://localhost/index.php/update/dxcc" - - name: Install Cypress - run: npm install cypress - - name: Run Cypress tests run: npx cypress run From ec8f4b4e5daab55ac728651ecf86840931e3fafd Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:18:29 -0500 Subject: [PATCH 20/37] 3 second delay was too fast --- .github/workflows/cypress-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml index f16d68c48..a8a2c9e70 100644 --- a/.github/workflows/cypress-tests.yml +++ b/.github/workflows/cypress-tests.yml @@ -36,7 +36,7 @@ jobs: run: docker-compose up -d - name: Wait for services to start - run: sleep 3 + run: sleep 5 - name: Populate dxcc_entities table run: curl "http://localhost/index.php/update/dxcc" From 6c06956e9a51b2cd621a35bf7f3c1cd1e40a5fef Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:29:50 -0500 Subject: [PATCH 21/37] add station logbook create tests --- cypress/e2e/5-station-logbook.cy.js | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 cypress/e2e/5-station-logbook.cy.js diff --git a/cypress/e2e/5-station-logbook.cy.js b/cypress/e2e/5-station-logbook.cy.js new file mode 100644 index 000000000..e0c3b7357 --- /dev/null +++ b/cypress/e2e/5-station-logbook.cy.js @@ -0,0 +1,44 @@ +describe("Create station logbook", () => { + beforeEach(() => { + cy.login(); + }); + + it("should load an empty list of station locations", () => { + cy.visit("/index.php/logbooks"); + + // Check that the table is not present + cy.get("#station_logbooks_table").should("not.exist"); + }); + + it("should have a button to create a new station location", () => { + cy.visit("/index.php/logbooks"); + + // Check that the button is present + cy.get("a").contains("Create Station Logbook").should("exist").click(); + + cy.url().should("include", "/logbooks/create"); + }); + + it("should create a new station location", () => { + cy.visit("/index.php/logbooks/create"); + + // Define the station location name + const stationLogbookName = "Home QTH"; + + // Type the station location name into the input field + cy.get('input[name="stationLogbook_Name"]').type(stationLogbookName); + + // Click the save button + cy.get('button[type="submit"]') + .contains("Create Station Logbook") + .click(); + + // Check if the station location was created successfully + cy.url().should("include", "/logbooks"); + + // // Check if the station location is present in the table + cy.get("#station_logbooks_table") + .contains(stationLogbookName) + .should("exist"); + }); +}); From f619a6b7026191958e52156e214aa460838f22f1 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 20:53:47 -0500 Subject: [PATCH 22/37] add a step to check that the link station button works --- cypress/e2e/5-station-logbook.cy.js | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/cypress/e2e/5-station-logbook.cy.js b/cypress/e2e/5-station-logbook.cy.js index e0c3b7357..e41134dca 100644 --- a/cypress/e2e/5-station-logbook.cy.js +++ b/cypress/e2e/5-station-logbook.cy.js @@ -4,6 +4,7 @@ describe("Create station logbook", () => { }); it("should load an empty list of station locations", () => { + // Navigate to the logbooks page cy.visit("/index.php/logbooks"); // Check that the table is not present @@ -11,6 +12,7 @@ describe("Create station logbook", () => { }); it("should have a button to create a new station location", () => { + // Navigate to the logbooks page cy.visit("/index.php/logbooks"); // Check that the button is present @@ -20,6 +22,7 @@ describe("Create station logbook", () => { }); it("should create a new station location", () => { + // Navigate to the create logbook page cy.visit("/index.php/logbooks/create"); // Define the station location name @@ -41,4 +44,40 @@ describe("Create station logbook", () => { .contains(stationLogbookName) .should("exist"); }); + + it("should set as active station logbook when button clicked", () => { + // Navigate to the logbooks page + cy.visit("/index.php/logbooks"); + + // Check that the button is present + cy.get("a").contains("Set as Active Logbook").should("exist").click(); + + // Check if the station was set to active + cy.get("body") + .contains("Active Logbook") + .should("be.visible") + .and("have.class", "badge text-bg-success"); + }); + + it("should link to a station location from the edit logbook page", () => { + // Navigate to the logbooks page + cy.visit("/index.php/logbooks"); + + // Click the edit button + cy.get("i.fas.fa-edit").should("exist").click(); + + // Ensure that the edit link navigates to the correct page + cy.url().should("include", "/logbooks/edit"); + + // Scroll to the bottom of the page + cy.scrollTo("bottom"); + + // Click the link location button + cy.get("button").contains("Link Location").should("exist").click(); + + // Make sure that our table now shows the linked station location + cy.get("#station_logbooks_linked_table") + .contains("Test Station Location") + .should("exist"); + }); }); From 253da3797cd81811e72723de6384120d5400c2d3 Mon Sep 17 00:00:00 2001 From: Patrick Burns Date: Sun, 7 Apr 2024 21:31:41 -0500 Subject: [PATCH 23/37] pause for the night on passing tests --- cypress/e2e/5-station-logbook.cy.js | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/cypress/e2e/5-station-logbook.cy.js b/cypress/e2e/5-station-logbook.cy.js index e41134dca..e1b4760c1 100644 --- a/cypress/e2e/5-station-logbook.cy.js +++ b/cypress/e2e/5-station-logbook.cy.js @@ -45,39 +45,39 @@ describe("Create station logbook", () => { .should("exist"); }); - it("should set as active station logbook when button clicked", () => { - // Navigate to the logbooks page - cy.visit("/index.php/logbooks"); + // it("should set as active station logbook when button clicked", () => { + // // Navigate to the logbooks page + // cy.visit("/index.php/logbooks"); - // Check that the button is present - cy.get("a").contains("Set as Active Logbook").should("exist").click(); + // // Check that the button is present + // cy.get("a").contains("Set as Active Logbook").should("exist").click(); - // Check if the station was set to active - cy.get("body") - .contains("Active Logbook") - .should("be.visible") - .and("have.class", "badge text-bg-success"); - }); + // // Check if the station was set to active + // cy.get("body") + // .contains("Active Logbook") + // .should("be.visible") + // .and("have.class", "badge text-bg-success"); + // }); - it("should link to a station location from the edit logbook page", () => { - // Navigate to the logbooks page - cy.visit("/index.php/logbooks"); + // it("should link to a station location from the edit logbook page", () => { + // // Navigate to the logbooks page + // cy.visit("/index.php/logbooks"); - // Click the edit button - cy.get("i.fas.fa-edit").should("exist").click(); + // // Click the edit button + // cy.get("i.fas.fa-edit").should("exist").click(); - // Ensure that the edit link navigates to the correct page - cy.url().should("include", "/logbooks/edit"); + // // Ensure that the edit link navigates to the correct page + // cy.url().should("include", "/logbooks/edit"); - // Scroll to the bottom of the page - cy.scrollTo("bottom"); + // // Scroll to the bottom of the page + // cy.scrollTo("bottom"); - // Click the link location button - cy.get("button").contains("Link Location").should("exist").click(); + // // Click the link location button + // cy.get("button").contains("Link Location").should("exist").click(); - // Make sure that our table now shows the linked station location - cy.get("#station_logbooks_linked_table") - .contains("Test Station Location") - .should("exist"); - }); + // // Make sure that our table now shows the linked station location + // cy.get("#station_logbooks_linked_table") + // .contains("Test Station Location") + // .should("exist"); + // }); }); From e7bb428bc479583766ca8fe305fdd8dced022e95 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 19 Apr 2024 16:08:58 +0100 Subject: [PATCH 24/37] Added bits to fix windows --- application/migrations/139_modify_eQSL_url.php | 3 +-- docker-compose.yml | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/application/migrations/139_modify_eQSL_url.php b/application/migrations/139_modify_eQSL_url.php index ab8cbba46..09e4fc370 100644 --- a/application/migrations/139_modify_eQSL_url.php +++ b/application/migrations/139_modify_eQSL_url.php @@ -12,5 +12,4 @@ public function down() { // Will not go back to insecure connections } -} -?> +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b6a3c29dc..b7218da6d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,8 @@ version: "3.8" +networks: + mynet: + services: web: build: . @@ -12,6 +15,8 @@ services: command: ["./script.sh"] depends_on: - db + networks: + - mynet db: build: @@ -21,5 +26,7 @@ services: - .env volumes: - db_data:/var/lib/mysql + networks: + - mynet volumes: db_data: {} From 1eac4e770dedee99cfc324d2bff4d05735ccebda Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 30 Apr 2024 11:32:41 +0100 Subject: [PATCH 25/37] Clean up --- assets/json/WABSquares.geojson | 484 +-------------------------------- 1 file changed, 1 insertion(+), 483 deletions(-) diff --git a/assets/json/WABSquares.geojson b/assets/json/WABSquares.geojson index ae0805aa4..1c3cb6e6c 100644 --- a/assets/json/WABSquares.geojson +++ b/assets/json/WABSquares.geojson @@ -12060,520 +12060,38 @@ {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.740638670299855,51.576834418824],[0.746057289590644,51.6666350561392],[0.890451743663082,51.6631678538776],[0.884749112985235,51.5733782923664],[0.740638670299855,51.576834418824]]]},"properties":{"name":"Small Square TQ99 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[0.815481695865424,51.6200305811172]},"properties":{"name":"TQ99"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.609118192314835,49.8918982662046],[-0.582612737625689,50.7909450183415],[0.834723129736035,50.7651002487293],[0.781771265779315,49.8668602666895],[-0.609118192314835,49.8918982662046]]]},"properties":{"name":"Large Square TV Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.609118192314835,49.8918982662046],[-0.606527896969274,49.9818016051831],[-0.467112494344517,49.9800431356106],[-0.469961760150837,49.8901453524817],[-0.609118192314835,49.8918982662046]]]},"properties":{"name":"Small Square TV00 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.538172984659304,49.9359975883031]},"properties":{"name":"TV00"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.606527637260101,49.9818105963411],[-0.603924239903771,50.0717124337124],[-0.464248532297415,50.0699483871002],[-0.467112208670416,49.9800521262119],[-0.606527637260101,49.9818105963411]]]},"properties":{"name":"Small Square TV01 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.53544603957452,50.0259064501365]},"properties":{"name":"TV01"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.603923978879961,50.0717214247202],[-0.601307393196254,50.1616217606349],[-0.461370063314203,50.1598521162039],[-0.464248245177381,50.0699573775493],[-0.603923978879961,50.0717214247202]]]},"properties":{"name":"Small Square TV02 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.532705291440504,50.1158138001782]},"properties":{"name":"TV02"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.601307130849138,50.1616307514925],[-0.598677269735497,50.2515295861089],[-0.458476991597678,50.2497543229348],[-0.461369774738699,50.1598611065007],[-0.601307130849138,50.1616307514925]]]},"properties":{"name":"Small Square TV03 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.529950649215097,50.2057196385121]},"properties":{"name":"TV03"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.598677006056323,50.2515385768164],[-0.596033781615377,50.3414359103003],[-0.455569220476638,50.3396550073124],[-0.458476701557081,50.2497633130794],[-0.598677006056323,50.2515385768164]]]},"properties":{"name":"Small Square TV04 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.527182021026342,50.2956239652291]},"properties":{"name":"TV04"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.596033516595315,50.3414449008577],[-0.593376840125902,50.4313407333824],[-0.452646652396011,50.4295541693621],[-0.455568928961237,50.3396639973046],[-0.596033516595315,50.3414449008577]]]},"properties":{"name":"Small Square TV05 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.524399314163115,50.3855267804271]},"properties":{"name":"TV05"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.59337657375604,50.4313497237897],[-0.590706355744101,50.5212440555359],[-0.449709188906846,50.5194518091157],[-0.452646359396007,50.4295631592022],[-0.59337657375604,50.4313497237897]]]},"properties":{"name":"Small Square TV06 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.521602435065642,50.4754280842105]},"properties":{"name":"TV06"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.590706088015445,50.5212530457931],[-0.588022238124797,50.6111458769489],[-0.446756730656168,50.6093479266107],[-0.449708894412348,50.5194607988035],[-0.590706088015445,50.5212530457931]]]},"properties":{"name":"Small Square TV07 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.518791289315868,50.5653278766906]},"properties":{"name":"TV07"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.588021969028272,50.6111548670561],[-0.585324396091253,50.7010461978167],[-0.443789177376691,50.6992425218907],[-0.446756434657195,50.6093569161464],[-0.588021969028272,50.6111548670561]]]},"properties":{"name":"Small Square TV08 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.515965781627712,50.6552261579854]},"properties":{"name":"TV08"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.5853241256177,50.7010551877737],[-0.582612737625689,50.7909450183415],[-0.440806427876399,50.7891355950049],[-0.44378887986317,50.6992515112741],[-0.5853241256177,50.7010551877737]]]},"properties":{"name":"Small Square TV09 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.513125815837173,50.7451229282193]},"properties":{"name":"TV09"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.469947843810261,49.890145168824],[-0.467098552108867,49.9800429513708],[-0.327697562266948,49.9781170068287],[-0.330805730362263,49.8882253088321],[-0.469947843810261,49.890145168824]]]},"properties":{"name":"Small Square TV10 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.398880308619976,49.9341580962526]},"properties":{"name":"TV10"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.467098266432169,49.980051941972],[-0.464234564033267,50.0699482022761],[-0.324573364140555,50.0680161499817],[-0.327697250634773,49.9781259968203],[-0.467098266432169,49.980051941972]]]},"properties":{"name":"Small Square TV11 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.395893734059535,50.0240611258729]},"properties":{"name":"TV11"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.464234276910623,50.0699571927251],[-0.461356068889857,50.1598519307933],[-0.321433342516465,50.1579137479944],[-0.324573050931222,50.0680251398188],[-0.464234276910623,50.0699571927251]]]},"properties":{"name":"Small Square TV12 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.392892043757255,50.1139626220087]},"properties":{"name":"TV12"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.46135578031173,50.15986092109],[-0.458462970880564,50.2497541369356],[-0.318277392920372,50.247809800721],[-0.321433027719573,50.1579227376769],[-0.46135578031173,50.15986092109]]]},"properties":{"name":"Small Square TV13 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.389875138028081,50.2038625845925]},"properties":{"name":"TV13"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.458462680837331,50.24976312708],[-0.455555173333311,50.3396548207222],[-0.315105409924992,50.3377043080207],[-0.318277076525428,50.247818790249],[-0.458462680837331,50.24976312708]]]},"properties":{"name":"Small Square TV14 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.386842916278554,50.2937610135627]},"properties":{"name":"TV14"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.455554881815261,50.3396638107144],[-0.452632578692143,50.4295539821788],[-0.311917287139298,50.4275972697571],[-0.315105091921404,50.3377132973941],[-0.455554881815261,50.3396638107144]]]},"properties":{"name":"Small Square TV15 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.383795276996553,50.3836579088629]},"properties":{"name":"TV15"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.452632285689476,50.4295629720188],[-0.449695088507216,50.5194516213371],[-0.308712917197608,50.5174886857989],[-0.311916967516378,50.427606258976],[-0.452632285689476,50.4295629720188]]]},"properties":{"name":"Small Square TV16 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.380732117740916,50.4735532704423]},"properties":{"name":"TV16"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.449694794010041,50.5194606110249],[-0.446742603424652,50.6093477382345],[-0.305492191748531,50.6073785560189],[-0.308712595944571,50.5174976748632],[-0.449694794010041,50.5194606110249]]]},"properties":{"name":"Small Square TV17 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.377653335130901,50.5634470982552]},"properties":{"name":"TV17"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.446742307422989,50.6093567277701],[-0.443775023176261,50.6992423329147],[-0.30225500144375,50.6972668802944],[-0.305491868854492,50.6073875449286],[-0.446742307422989,50.6093567277701]]]},"properties":{"name":"Small Square TV18 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.374558824835517,50.6533393922613]},"properties":{"name":"TV18"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.443774725660036,50.699251322298],[-0.440792246569107,50.7891354054267],[-0.299001235926663,50.7871536585069],[-0.302254676897723,50.6972758690495],[-0.443774725660036,50.699251322298]]]},"properties":{"name":"Small Square TV19 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.3714484815627,50.7432301524253]},"properties":{"name":"TV19"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.330791815518688,49.8882251084802],[-0.327683621538133,49.9781168058418],[-0.188298352300565,49.9760234298199],[-0.191665320088284,49.8861383454455],[-0.330791815518688,49.8882251084802]]]},"properties":{"name":"Small Square TV20 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.259602651682817,49.9321513982909]},"properties":{"name":"TV20"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.327683309903362,49.9781257958333],[-0.324559397393166,50.0680159483575],[-0.184914021633607,50.0659159341361],[-0.188298014720624,49.9760324191488],[-0.327683309903362,49.9781257958333]]]},"properties":{"name":"Small Square TV21 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.256356546440312,50.0220480660429]},"properties":{"name":"TV21"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.324559084181225,50.0680249381945],[-0.321419349618892,50.1579135457304],[-0.18151255184976,50.1558068685866],[-0.184913682345376,50.065924923308],[-0.324559084181225,50.0680249381945]]]},"properties":{"name":"Small Square TV22 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.25309401366169,50.1119431766523]},"properties":{"name":"TV22"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.321419034819379,50.1579225354129],[-0.318263373740137,50.2478095978149],[-0.178093829808237,50.245696232853],[-0.181512210841976,50.1558158576015],[-0.321419034819379,50.1579225354129]]]},"properties":{"name":"Small Square TV23 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.249814945029117,50.2018367298868]},"properties":{"name":"TV23"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.318263057342558,50.2478185873428],[-0.315091364328744,50.33770410447],[-0.174657741336433,50.3355840266202],[-0.178093487069536,50.2457052217109],[-0.318263057342558,50.2478185873428]]]},"properties":{"name":"Small Square TV24 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.246519231237879,50.2917287255179]},"properties":{"name":"TV24"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.315091046322507,50.3377130938434],[-0.3119032149928,50.4275970655595],[-0.171204171218276,50.4254702495763],[-0.174657396855345,50.335593015321],[-0.315091046322507,50.3377130938434]]]},"properties":{"name":"Small Square TV25 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.243206761985249,50.3816191633215]},"properties":{"name":"TV25"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.311902895367218,50.4276060547783],[-0.308698818365733,50.5174884809519],[-0.167733003182415,50.5153549014125],[-0.171203824983227,50.4254792381201],[-0.311902895367218,50.4276060547783]]]},"properties":{"name":"Small Square TV26 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.239877425959205,50.4715080430772]},"properties":{"name":"TV26"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.308698497110021,50.5174974700161],[-0.305478066095253,50.60737835052],[-0.164244119890251,50.6052379818228],[-0.167732655181725,50.5153638897991],[-0.308698497110021,50.5174974700161]]]},"properties":{"name":"Small Square TV27 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.236531110826995,50.5613953645683]},"properties":{"name":"TV27"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.305477743198525,50.6073873394297],[-0.302240848832135,50.6972666741411],[-0.1607374029238,50.695119490504],[-0.164243770112132,50.6052469700523],[-0.305477743198525,50.6073873394297]]]},"properties":{"name":"Small Square TV28 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.233167703223538,50.6512811275818]},"properties":{"name":"TV28"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.302240524283406,50.6972756628962],[-0.298987056218862,50.7871534516969],[-0.157212732773396,50.7849994271554],[-0.160737051356355,50.6951284785762],[-0.302240524283406,50.6972756628962]]]},"properties":{"name":"Small Square TV29 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.229787088739678,50.7411653319084]},"properties":{"name":"TV29"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.191651406871609,49.8861381284039],[-0.188284413209335,49.9760232120904],[-0.0489161714662353,49.973762451849],[-0.0525418278393301,49.8838845093009],[-0.191651406871609,49.8861381284039]]]},"properties":{"name":"Small Square TV30 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.120341317076965,49.9299775396603]},"properties":{"name":"TV30"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.188284075626799,49.9760322014193],[-0.184900056534587,50.0659157157163],[-0.0452718203858165,50.0636477871168],[-0.048915807949689,49.9737714404624],[-0.188284075626799,49.9760322014193]]]},"properties":{"name":"Small Square TV31 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.116835788501027,50.0198673161649]},"properties":{"name":"TV31"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.184899717243748,50.0659247048881],[-0.181498560611437,50.1558066494738],[-0.0416090155896735,50.1535315258248],[-0.0452714550299508,50.0636567755705],[-0.184899717243748,50.0659247048881]]]},"properties":{"name":"Small Square TV32 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.113312521570628,50.1097555099058]},"properties":{"name":"TV32"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.181498219601033,50.1558156384886],[-0.178079812298233,50.2456960130446],[-0.0379276352820328,50.2434136674684],[-0.0416086483823644,50.1535405141188],[-0.181498219601033,50.1558156384886]]]},"properties":{"name":"Small Square TV33 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.109771399346134,50.199642120472]},"properties":{"name":"TV33"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.178079469556898,50.2457050019024],[-0.174643697421496,50.3355838061137],[-0.0342275565566212,50.3332942115446],[-0.0379272662110457,50.2434226556027],[-0.178079469556898,50.2457050019024]]]},"properties":{"name":"Small Square TV34 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.10621230382271,50.2895271474549]},"properties":{"name":"TV34"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.174643352937761,50.3355927948144],[-0.171190100764273,50.425470028369],[-0.03050865538413,50.4231731575516],[-0.0342271856096091,50.333303199519],[-0.174643352937761,50.3355927948144]]]},"properties":{"name":"Small Square TV35 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.102635115918303,50.3794105904482]},"properties":{"name":"TV35"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.171189754526563,50.4254790169127],[-0.16771890605432,50.5153546795018],[-0.0267708065995082,50.5130505049894],[-0.0305082825486328,50.4231821453663],[-0.171189754526563,50.4254790169127]]]},"properties":{"name":"Small Square TV36 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.0990397154614751,50.4692924490482]},"properties":{"name":"TV36"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.167718558050956,50.5153636678883],[-0.164229995952143,50.605237759206],[-0.0230138838890848,50.6029262533588],[-0.0267704318629527,50.5130594926442],[-0.167718558050956,50.5153636678883]]]},"properties":{"name":"Small Square TV37 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.0954259811790516,50.5591727228529]},"properties":{"name":"TV37"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.164229646171336,50.6052467474353],[-0.160723252038849,50.6951192671783],[-0.0192377597775104,50.6928004021618],[-0.0230135072387823,50.6029352408536],[-0.164229646171336,50.6052467474353]]]},"properties":{"name":"Small Square TV38 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.0917937906836191,50.6490514114627]},"properties":{"name":"TV38"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.160722900468703,50.6951282552505],[-0.15719855480386,50.7849992031183],[-0.0154423056145235,50.7826729509011],[-0.0192373812006535,50.6928093894966],[-0.160722900468703,50.6951282552505]]]},"properties":{"name":"Small Square TV39 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-0.088143020460839,50.7389285144795]},"properties":{"name":"TV39"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0525279163793566,49.8838842755745],[-0.0489022341432425,49.973762217382],[0.0904476742237165,49.9713341239489],[0.0865634488715219,49.8814638511219],[-0.0525279163793566,49.8838842755745]]]},"properties":{"name":"Small Square TV40 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.018902392933086,49.9276365693615]},"properties":{"name":"TV40"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0489018706241031,49.9737712059953],[-0.0452578570666753,50.0636475519064],[0.0943519250134505,50.061211760268],[0.0904480636648509,49.9713431117937],[-0.0489018706241031,49.9737712059953]]]},"properties":{"name":"Small Square TV41 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0226672289496161,50.0175189255383]},"properties":{"name":"TV41"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0452574917082039,50.06365654036],[-0.041595026142978,50.1535312898682],[0.0982759430195802,50.1510877713674],[0.0943523164248252,50.0612207479504],[-0.0452574917082039,50.06365654036]]]},"properties":{"name":"Small Square TV42 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0264511130855698,50.1073996713698]},"properties":{"name":"TV42"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0415946589330494,50.1535402781622],[-0.0379136195755114,50.2434134307629],[0.102219858680498,50.2409621565423],[0.0982763364141794,50.1510967588872],[-0.0415946589330494,50.1535402781622]]]},"properties":{"name":"Small Square TV43 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0302541708905274,50.1972788062527]},"properties":{"name":"TV43"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0379132505018913,50.2434224188971],[-0.0342135144571301,50.3332939740872],[0.106183803623611,50.330834915088],[0.102220254071425,50.2409711438995],[-0.0379132505018913,50.2434224188971]]]},"properties":{"name":"Small Square TV44 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0340765290574333,50.2871563295843]},"properties":{"name":"TV44"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0342131435074716,50.3333029620617],[-0.0304945867576445,50.4231729193397],[0.110167910678756,50.4207060462993],[0.106184201024088,50.3308439022825],[-0.0342131435074716,50.3333029620617]]]},"properties":{"name":"Small Square TV45 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0379183154354882,50.3770322407626]},"properties":{"name":"TV45"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0304942139194878,50.4231819071543],[-0.0267567113111149,50.51305026602],[0.114172313891805,50.5105755494705],[0.110168310102127,50.420715033331],[-0.0304942139194878,50.4231819071543]]]},"properties":{"name":"Small Square TV46 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0417796590432091,50.4669065391864]},"properties":{"name":"TV46"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0267563365718864,50.5130592536747],[-0.0229997618029737,50.6029260136291],[0.118197148538443,50.6004434238953],[0.114172715351535,50.5105845363394],[-0.0267563365718864,50.5130592536747]]]},"properties":{"name":"Small Square TV47 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0456606900816779,50.5567792242544]},"properties":{"name":"TV47"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0229993851499845,50.6029350011239],[-0.0192236107569658,50.6928001616689],[0.122242551138153,50.6903096688666],[0.118197552048122,50.6004524106013],[-0.0229993851499845,50.6029350011239]]]},"properties":{"name":"Small Square TV48 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.0495615399479619,50.6466502953659]},"properties":{"name":"TV48"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-0.0192232321774088,50.6928091490037],[-0.015428129521917,50.7826727096422],[0.126308659468374,50.780174283676],[0.122242956711497,50.6903186554096],[-0.0192232321774088,50.6928091490037]]]},"properties":{"name":"Small Square TV49 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[0.0534823412487249,50.7365197519199]},"properties":{"name":"TV49"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.0865773584450946,49.881463600716],[0.0904616096479229,49.9713338727495],[0.2297918798424,49.9687385009158],[0.225649213604594,49.8788764253735],[0.0865773584450946,49.881463600716]]]},"properties":{"name":"Small Square TV50 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.158127177124029,49.9251285401494]},"properties":{"name":"TV50"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.0904619990916495,49.9713428605943],[0.0943658864213067,50.0612115082723],[0.233955901072465,50.0586079087205],[0.229792295195255,49.9687474879393],[0.0904619990916495,49.9713428605943]]]},"properties":{"name":"Small Square TV51 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.162151196155798,50.0150029472397]},"properties":{"name":"TV51"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.0943662778352862,50.0612204959546],[0.0982899305423781,50.1510875185723],[0.238141001843793,50.1484756606821],[0.233956318526364,50.0586168955785],[0.0943662778352862,50.0612204959546]]]},"properties":{"name":"Small Square TV52 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.166195571941275,50.1048757144452]},"properties":{"name":"TV52"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.0982903239395956,50.151096506092],[0.102233872450394,50.2409619029449],[0.242347321224156,50.2383417558826],[0.238141421412578,50.1484846473745],[0.0982903239395956,50.151096506092]]]},"properties":{"name":"Small Square TV53 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.170260438627271,50.1947468409566]},"properties":{"name":"TV53"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.102234267843952,50.240970890302],[0.106197843773633,50.3308346606853],[0.246574999548677,50.3282061934013],[0.242347742921799,50.2383507424092],[0.102234267843952,50.240970890302]]]},"properties":{"name":"Small Square TV54 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.174345931581949,50.2846163259637]},"properties":{"name":"TV54"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.106198241176754,50.3308436478797],[0.110181977342811,50.4207057910882],[0.250824178434121,50.4180689723158],[0.246575423389273,50.3282151797622],[0.106198241176754,50.3308436478797]]]},"properties":{"name":"Small Square TV55 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.178452187408591,50.3744841686548]},"properties":{"name":"TV55"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.11018237676884,50.4207147781199],[0.114186407204687,50.510575293448],[0.255095000793392,50.507930091701],[0.250824604431899,50.4180779585108],[0.11018237676884,50.4207147781199]]]},"properties":{"name":"Small Square TV56 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.18257934395955,50.4643503682171]},"properties":{"name":"TV56"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.114186808667089,50.5105842803168],[0.118211268635843,50.6004431670584],[0.25938761085022,50.5977895506291],[0.255095428962707,50.5079390777299],[0.114186808667089,50.5105842803168]]]},"properties":{"name":"Small Square TV57 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.186727540350392,50.5542149238363]},"properties":{"name":"TV57"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.118211672148207,50.6004521537642],[0.122256698156664,50.690309411212],[0.26370215415405,50.6876473481696],[0.25938804120556,50.597798536492],[0.118211672148207,50.6004521537642]]]},"properties":{"name":"Small Square TV58 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.190896916974229,50.6440778346959]},"properties":{"name":"TV58"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.122257103732706,50.6903183977549],[0.126322833545501,50.7801740252008],[0.26803877759514,50.7775034833889],[0.263702586710039,50.6876563338663],[0.122257103732706,50.6903183977549]]]},"properties":{"name":"Small Square TV59 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[0.195087615516255,50.7339390999781]},"properties":{"name":"TV59"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.225663121162178,49.8788761582937],[0.229805813237385,49.9687382329898],[0.3691151416251,49.9659756413061],[0.364714171069497,49.8761222902577],[0.225663121162178,49.8788761582937]]]},"properties":{"name":"Small Square TV60 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.297331735390141,49.9224535085296]},"properties":{"name":"TV60"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.22980622859283,49.9687472200133],[0.233969860437745,50.0586076399452],[0.373538795474733,50.0558362913877],[0.369115582875954,49.9659846274555],[0.22980622859283,49.9687472200133]]]},"properties":{"name":"Small Square TV61 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.301614804491827,50.0123194381188]},"properties":{"name":"TV61"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.233970277894247,50.0586166268031],[0.238154987310538,50.1484753910544],[0.377984839937225,50.1456952530429],[0.37353923895731,50.0558452773683],[0.233970277894247,50.0586166268031]]]},"properties":{"name":"Small Square TV62 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.305919537773705,50.1021836963289]},"properties":{"name":"TV62"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.23815540688194,50.1484843777466],[0.242361332924401,50.2383414853991],[0.382453422695626,50.2355525251261],[0.377985285666226,50.1457042388545],[0.23815540688194,50.1484843777466]]]},"properties":{"name":"Small Square TV63 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.310246077966235,50.192046282131]},"properties":{"name":"TV63"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.242361754624673,50.2383504719257],[0.246589037615324,50.328205922059],[0.386944692778473,50.3254081064877],[0.382453870685886,50.2355615107687],[0.242361754624673,50.2383504719257]]]},"properties":{"name":"Small Square TV64 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.314594569099032,50.2819071944933]},"properties":{"name":"TV64"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.246589461458564,50.3282149084198],[0.250838243000952,50.4180687001114],[0.391458800574971,50.4152619959737],[0.386945143044964,50.3254170919612],[0.246589461458564,50.3282149084198]]]},"properties":{"name":"Small Square TV65 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.31896515651551,50.371766432381]},"properties":{"name":"TV65"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.250838669001386,50.4180776863063],[0.255109091995075,50.5079298186313],[0.395995897850366,50.5051141924258],[0.391459253132799,50.415270981278],[0.250838669001386,50.4180776863063]]]},"properties":{"name":"Small Square TV66 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.323357986887714,50.4616239947558]},"properties":{"name":"TV66"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.25510952016706,50.5079388046601],[0.259401728822315,50.5977892766908],[0.400556137761538,50.5949646946807],[0.395996352714777,50.5051231775607],[0.25510952016706,50.5079388046601]]]},"properties":{"name":"Small Square TV67 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.327773208231357,50.5514798805758]},"properties":{"name":"TV67"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.259402159180339,50.5977982625535],[0.263716299033022,50.6876470733593],[0.405139674872805,50.6848135015702],[0.400556594947917,50.5949736796461],[0.259402159180339,50.5977982625535]]]},"properties":{"name":"Small Square TV68 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.332210969921068,50.6413340887953]},"properties":{"name":"TV68"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.263716731591708,50.6876560590559],[0.268052949518363,50.7775032077034],[0.40974666517194,50.774660611921],[0.405140134396682,50.6848224863661],[0.263716731591708,50.6876560590559]]]},"properties":{"name":"Small Square TV69 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[0.33667142270584,50.7311866183648]},"properties":{"name":"TV69"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.364728076481624,49.8761220065099],[0.369129072860547,49.9659753566595],[0.508416157045829,49.9630456074313],[0.503757027200845,49.8732015077092],[0.364728076481624,49.8761220065099]]]},"properties":{"name":"Small Square TV70 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.436514768819507,49.9196115347537]},"properties":{"name":"TV70"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.369129514113991,49.9659843428088],[0.373552752666265,50.0558360058389],[0.513099297156403,50.0528969709613],[0.508416624180114,49.9630545926538],[0.369129514113991,49.9659843428088]]]},"properties":{"name":"Small Square TV71 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.441056746539218,50.0094684587947]},"properties":{"name":"TV71"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.373553196151445,50.0558449918194],[0.377998823215885,50.1456949665885],[0.517806137620888,50.1427466115243],[0.513099766652957,50.0529059560116],[0.373553196151445,50.0558449918194]]]},"properties":{"name":"Small Square TV72 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.445621694580862,50.09932367801]},"properties":{"name":"TV72"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.377999268947502,50.1457039524001],[0.382467432193316,50.2355522377627],[0.522536834722638,50.2325945277341],[0.517806609495269,50.1427555964022],[0.377999268947502,50.1457039524001]]]},"properties":{"name":"Small Square TV73 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.450209764244104,50.189177191138]},"properties":{"name":"TV73"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.382467880186204,50.2355612234053],[0.386958728627965,50.3254078182119],[0.527291546168435,50.3224407181978],[0.522537308990545,50.2326035124394],[0.382467880186204,50.2355612234053]]]},"properties":{"name":"Small Square TV74 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.454821108205377,50.2790289969119]},"properties":{"name":"TV74"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.386959178897097,50.3254168036854],[0.391472862909912,50.4152617067822],[0.532070431104538,50.4122851815167],[0.52729202284571,50.3224497027306],[0.386959178897097,50.3254168036854]]]},"properties":{"name":"Small Square TV75 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.459455880533388,50.3688790940595]},"properties":{"name":"TV75"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.391473315470395,50.4152706920865],[0.396009986805288,50.5051139023151],[0.536873650132949,50.5021279162849],[0.532070910207169,50.4122941658767],[0.391473315470395,50.4152706920865]]]},"properties":{"name":"Small Square TV76 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.464114236704837,50.4587274813032]},"properties":{"name":"TV76"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.396010441672368,50.5051228874499],[0.400570253471866,50.5949644036472],[0.541701365327895,50.5919689210896],[0.536874131677069,50.5021369004719],[0.396010441672368,50.5051228874499]]]},"properties":{"name":"Small Square TV77 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.468796333620343,50.5485741573599]},"properties":{"name":"TV77"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.400570710660928,50.5949733886126],[0.405153817474865,50.6848132096105],[0.546553740252547,50.6818081945108],[0.541701849329785,50.5919779051035],[0.400570710660928,50.5949733886126]]]},"properties":{"name":"Small Square TV78 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.473502329620597,50.6384191209402]},"properties":{"name":"TV78"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.405154277001437,50.6848221944063],[0.409760834802967,50.7746603190316],[0.551430939975955,50.7716457351212],[0.54655422672864,50.6818171783515],[0.405154277001437,50.6848221944063]]]},"properties":{"name":"Small Square TV79 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.478232384502727,50.7282623707486]},"properties":{"name":"TV79"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.50377093033817,49.8732012072999],[0.50843008599155,49.9630453060706],[0.647693624893706,49.959948465354],[0.64277648923378,49.870114143391],[0.50377093033817,49.8732012072999]]]},"properties":{"name":"Small Square TV80 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.57567497977006,49.9166026828153]},"properties":{"name":"TV80"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.508430553128423,49.9630542912929],[0.513113252043147,50.0528966686455],[0.652636096383497,50.0497900139066],[0.647694117896002,49.9599574495968],[0.508430553128423,49.9630542912929]]]},"properties":{"name":"Small Square TV81 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.580475716163582,50.0064500736505]},"properties":{"name":"TV81"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.513113721542302,50.0529056536956],[0.51782011857956,50.1427463082499],[0.657603576560632,50.139629802998],[0.65263659187847,50.0497989979735],[0.513113721542302,50.0529056536956]]]},"properties":{"name":"Small Square TV82 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.585300727659284,50.096295724265]},"properties":{"name":"TV82"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.517820590456555,50.1427552931276],[0.522550841885003,50.2325942234973],[0.662596230292936,50.2294678309874],[0.657604074564694,50.1396387868888],[0.517820590456555,50.1427552931276]]]},"properties":{"name":"Small Square TV83 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.590150174110736,50.1861396331505]},"properties":{"name":"TV83"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.522551316155537,50.2326032082026],[0.527305579667124,50.3224404129953],[0.667614223949385,50.3193040962258],[0.662596730822646,50.2294768147021],[0.522551316155537,50.2326032082026]]]},"properties":{"name":"Small Square TV84 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.595024216825682,50.2759817987917]},"properties":{"name":"TV84"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.527306056347039,50.3224493975279],[0.532084491073057,50.4122848753448],[0.672657725417031,50.4091385970552],[0.667614727021458,50.3193130797641],[0.527306056347039,50.3224493975279]]]},"properties":{"name":"Small Square TV85 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.59992301858241,50.3658222196655]},"properties":{"name":"TV85"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.532084970178341,50.4122938597046],[0.536887736705686,50.5021276091398],[0.677726904118141,50.4989713318085],[0.672658231048331,50.409147580417],[0.532084970178341,50.4122938597046]]]},"properties":{"name":"Small Square TV86 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.60484674364634,50.4556608942412]},"properties":{"name":"TV86"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.536888218252474,50.5021365933267],[0.541715478640131,50.5919686129677],[0.682821931027582,50.5888022988095],[0.677727412325689,50.4989803149936],[0.536888218252474,50.5021365933267]]]},"properties":{"name":"Small Square TV87 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.60979555778685,50.5454978209801]},"properties":{"name":"TV87"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.541715962644702,50.5919775969816],[0.546567880440461,50.6818078854085],[0.687942978690433,50.6786314963723],[0.682822441828551,50.5888112818178],[0.541715962644702,50.5919775969816]]]},"properties":{"name":"Small Square TV88 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.614769628294324,50.6353329983353]},"properties":{"name":"TV88"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.546568366919249,50.6818168692492],[0.551445107176633,50.7716454250347],[0.693090221239851,50.7684589228011],[0.68794349210216,50.6786404792035],[0.546568366919249,50.6818168692492]]]},"properties":{"name":"Small Square TV89 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.619769123997434,50.7251664247511]},"properties":{"name":"TV89"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.642790389967097,49.8701138263269],[0.647707551419648,49.9599481472858],[0.786946245349119,49.9566842848824],[0.781771265779315,49.8668602666895],[0.642790389967097,49.8701138263269]]]},"properties":{"name":"Small Square TV90 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.714811071945438,49.913427020445]},"properties":{"name":"TV90"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.647708044424531,49.9599571315285],[0.652650048834549,50.0497896948305],[0.79214788482893,50.0465154904573],[0.786946764203162,49.9566932680927],[0.647708044424531,49.9599571315285]]]},"properties":{"name":"Small Square TV91 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.719870408591326,50.0032643508293]},"properties":{"name":"TV91"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.652650544332121,50.0497986788973],[0.657617555067554,50.1396294829102],[0.797375839845031,50.1363448981265],[0.792148406305909,50.046524473488],[0.652650544332121,50.0497986788973]]]},"properties":{"name":"Small Square TV92 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.724955323681598,50.0930999036526]},"properties":{"name":"TV92"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.657618053074228,50.139638466801],[0.662610234987345,50.2294675098843],[0.802630283833027,50.2261725059816],[0.797376363962211,50.1363538809773],[0.657618053074228,50.139638466801]]]},"properties":{"name":"Small Square TV93 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.730065985607581,50.1829336771467]},"properties":{"name":"TV93"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.662610735519681,50.2294764935989],[0.667628254963766,50.3193037741034],[0.807911391807174,50.3159983121032],[0.802630810607828,50.2261814886523],[0.662610735519681,50.2294764935989]]]},"properties":{"name":"Small Square TV94 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.735202564291957,50.2727656695339]},"properties":{"name":"TV94"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.667628758038477,50.3193127576416],[0.672671782884739,50.4091382739097],[0.813219340378169,50.4058223145606],[0.807911921257179,50.3160072945936],[0.667628758038477,50.3193127576416]]]},"properties":{"name":"Small Square TV95 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.740365231205996,50.3625958790266]},"properties":{"name":"TV95"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.672672288518691,50.4091472572714],[0.677740988173415,50.4989710076362],[0.818554307771166,50.4956445114119],[0.813219872521118,50.4058312968706],[0.672672288518691,50.4091472572714]]]},"properties":{"name":"Small Square TV96 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.745554159387023,50.4524243038272]},"properties":{"name":"TV96"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.677741496383628,50.4989799908212],[0.682836041805548,50.5888019736064],[0.823916473844049,50.5854649007031],[0.818554842624964,50.4956534935412],[0.677741496383628,50.4989799908212]]]},"properties":{"name":"Small Square TV97 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.750769523456125,50.5422509421275]},"properties":{"name":"TV97"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.682836552609196,50.5888109566146],[0.687957116327117,50.6786311701345],[0.829306020105953,50.6752834804684],[0.823917011426763,50.5854738826516],[0.682836552609196,50.5888109566146]]]},"properties":{"name":"Small Square TV98 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.756011499636098,50.6320757921089]},"properties":{"name":"TV98"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[0.687957629741536,50.6786401529656],[0.693104385872181,50.7684585955247],[0.834723129736035,50.7651002487293],[0.829306560435819,50.6752924622358],[0.687957629741536,50.6786401529656]]]},"properties":{"name":"Small Square TV99 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[0.761280265769636,50.7218988519417]},"properties":{"name":"TV99"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00120435768874,49.6506715122516],[-3.00120707268857,49.7405949274282],[-2.86245218592938,49.7405133689641],[-2.86270526111388,49.6505902108797],[-3.00120435768874,49.6506715122516]]]},"properties":{"name":"Small Square WA00 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93188528077592,49.6956179132001]},"properties":{"name":"WA00"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00120707296077,49.740603920599],[-3.00120980145015,49.8305259343628],[-2.86219781005146,49.8304441178356],[-2.8624521605557,49.7405223621091],[-3.00120707296077,49.740603920599]]]},"properties":{"name":"Small Square WA01 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93175975981844,49.7855495575504]},"properties":{"name":"WA01"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.0012098017237,49.8305349273934],[-3.00121254379112,49.9204555405397],[-2.86194215037723,49.9203734649974],[-2.86219778454982,49.8304531108403],[-3.0012098017237,49.8305349273934]]]},"properties":{"name":"Small Square WA02 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93163360575266,49.8754798005117]},"properties":{"name":"WA02"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00121254406603,49.9204645334303],[-3.00121529980079,50.0103837467677],[-2.86168519848163,50.0103014112518],[-2.86194212474679,49.920382457862],[-3.00121254406603,49.9204645334303]]]},"properties":{"name":"Small Square WA03 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93150681442898,49.9654086428845]},"properties":{"name":"WA03"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00121530007708,50.0103927395184],[-3.00121806956928,50.1003105538696],[-2.86142694586312,50.1002279574149],[-2.86168517272154,50.0103104039764],[-3.00121530007708,50.0103927395184]]]},"properties":{"name":"Small Square WA04 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93137938166016,50.055336085483]},"properties":{"name":"WA04"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00121806984695,50.1003195464804],[-3.00122085318753,50.1902359626817],[-2.86116738394283,50.1901531043163],[-2.86142691997253,50.1002369499996],[-3.00121806984695,50.1003195464804]]]},"properties":{"name":"Small Square WA05 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93125130322093,50.145262129135]},"properties":{"name":"WA05"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00122085346659,50.1902449551527],[-3.00122365074729,50.2801599740541],[-2.86090650406365,50.2800768527991],[-2.86116735792087,50.190162096761],[-3.00122085346659,50.1902449551527]]]},"properties":{"name":"Small Square WA06 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93112257484754,50.2351867746822]},"properties":{"name":"WA06"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00122365102775,50.2801689663854],[-3.00122646234118,50.3700825888505],[-2.86064429748942,50.3699992037204],[-2.86090647790947,50.2800858451041],[-3.00122365102775,50.2801689663854]]]},"properties":{"name":"Small Square WA07 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93099319223731,50.3251100229797]},"properties":{"name":"WA07"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00122646262304,50.3700915810422],[-3.00122928806263,50.4600038079485],[-2.86038075540398,50.4599201579508],[-2.86064427120213,50.3700081958857],[-3.00122646262304,50.3700915810422]]]},"properties":{"name":"Small Square WA08 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93086315104823,50.4150318748965]},"properties":{"name":"WA08"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00122928834592,50.4600128000007],[-3.00123212800596,50.5499236322392],[-2.86011586891025,50.5498397163743],[-2.86038072898269,50.4599291499764],[-3.00122928834592,50.4600128000007]]]},"properties":{"name":"Small Square WA09 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93073244689847,50.5049523313153]},"properties":{"name":"WA09"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86269140986122,49.650590194464],[-2.86243830909543,49.7405133524965],[-2.72368469996145,49.7402655924957],[-2.72419358263006,49.6503432160662],[-2.86269140986122,49.650590194464]]]},"properties":{"name":"Small Square WA10 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79324504907867,49.6954534886538]},"properties":{"name":"WA10"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86243828371918,49.7405223456415],[-2.86218390750474,49.8304441013158],[-2.72317320208845,49.8301955567562],[-2.72368464894015,49.7402745855624],[-2.86243828371918,49.7405223456415]]]},"properties":{"name":"Small Square WA11 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79286304633386,49.7853846125692]},"properties":{"name":"WA11"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86218388200052,49.8304530943206],[-2.86192822198801,49.9203734484253],[-2.72265912298939,49.920124116409],[-2.72317315080987,49.8302045496823],[-2.86218388200052,49.8304530943206]]]},"properties":{"name":"Small Square WA12 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79247911723149,49.8753143331772]},"properties":{"name":"WA12"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86192819635497,49.9203824412899],[-2.8616712441193,50.0103013946272],[-2.72214244572481,50.0100512722363],[-2.72265907145184,49.9201331091947],[-2.86192819635497,49.9203824412899]]]},"properties":{"name":"Small Square WA13 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79209324914536,49.9652426512647]},"properties":{"name":"WA13"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86167121835661,50.0103103873518],[-2.86141296539623,50.1002279407376],[-2.72162315320153,50.0999770250336],[-2.7221423939266,50.0100602648817],[-2.86167121835661,50.0103103873518]]]},"properties":{"name":"Small Square WA14 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79170542933479,50.0551695676327]},"properties":{"name":"WA14"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86141293950302,50.1002369333222],[-2.86115337723904,50.190153087586],[-2.72110122817085,50.1899013756102],[-2.72162310114093,50.0999860175388],[-2.86141293950302,50.1002369333222]]]},"properties":{"name":"Small Square WA15 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79131564494334,50.1450950830953]},"properties":{"name":"WA15"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86115335121446,50.1901620800307],[-2.86089247098978,50.2800768360158],[-2.72057665322685,50.2798243247886],[-2.72110117584613,50.1899103679752],[-2.86115335121446,50.1901620800307]]]},"properties":{"name":"Small Square WA16 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79092388299747,50.2350191984804]},"properties":{"name":"WA16"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86089244483295,50.2800858283207],[-2.86063023791138,50.3699991868838],[-2.72004941080457,50.3697458734049],[-2.72057660063626,50.2798333170135],[-2.86089244483295,50.2800858283207]]]},"properties":{"name":"Small Square WA17 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79053013040526,50.3249419146295]},"properties":{"name":"WA17"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86063021162143,50.370008179049],[-2.86036666918678,50.4599201410606],[-2.71951948317826,50.4596660223084],[-2.72004935794635,50.3697548654897],[-2.86063021162143,50.370008179049]]]},"properties":{"name":"Small Square WA18 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79013437395505,50.4148632323975]},"properties":{"name":"WA18"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86036664276282,50.4599291330862],[-2.86010175591803,50.5498396994304],[-2.71898685245951,50.5495847723622],[-2.71951943005063,50.4596750142534],[-2.86036664276282,50.4599291330862]]]},"properties":{"name":"Small Square WA19 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.78973660031408,50.5047831526532]},"properties":{"name":"WA19"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72417973156838,49.6503431830813],[-2.72367082331972,49.7402655594064],[-2.58491978066245,49.7398516034257],[-2.58568445417185,49.6499305331809],[-2.72417973156838,49.6503431830813]]]},"properties":{"name":"Small Square WA20 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65460673345794,49.6951231107514]},"properties":{"name":"WA20"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72367077229585,49.7402745524731],[-2.72315929973522,49.8301955235621],[-2.5841511775898,49.8297802565606],[-2.58491970399521,49.7398605963615],[-2.72367077229585,49.7402745524731]]]},"properties":{"name":"Small Square WA21 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65396826144685,49.7850531886654]},"properties":{"name":"WA21"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72315924845406,49.8302045164883],[-2.72264519479492,49.9201240831098],[-2.58337869601342,49.9197075002439],[-2.58415110053597,49.8297892493554],[-2.72315924845406,49.8302045164883]]]},"properties":{"name":"Small Square WA22 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.6533265699422,49.8749818594141]},"properties":{"name":"WA22"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72264514325478,49.9201330758955],[-2.72212849155852,50.0100512388315],[-2.58260231048121,50.0096333352242],[-2.58337861857047,49.9197164928979],[-2.72264514325478,49.9201330758955]]]},"properties":{"name":"Small Square WA23 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65268163784248,49.9649091237579]},"properties":{"name":"WA23"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.7221284397577,50.0100602314769],[-2.72160917293196,50.0999769915229],[-2.58182199531004,50.0995577622631],[-2.58260223264659,50.0096423277373],[-2.7221284397577,50.0100602314769]]]},"properties":{"name":"Small Square WA24 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65203344385486,50.0548349824703]},"properties":{"name":"WA24"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72160912086874,50.099985984028],[-2.7210872216657,50.1899013419931],[-2.58103772458316,50.1894807821353],[-2.58182191708116,50.0995667546354],[-2.72160912086874,50.099985984028]]]},"properties":{"name":"Small Square WA25 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.651381966493,50.1447594363385]},"properties":{"name":"WA25"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72108716933835,50.1899103343581],[-2.72056262035292,50.2798242910648],[-2.58024947214758,50.2794023956289],[-2.58103764595742,50.1894897743669],[-2.72108716933835,50.1899103343581]]]},"properties":{"name":"Small Square WA26 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65072718407494,50.2346824861627]},"properties":{"name":"WA26"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72056256775969,50.2798332832896],[-2.7200353514278,50.3697458395739],[-2.57945721161138,50.369322603545],[-2.58024939312235,50.2794113877199],[-2.72056256775969,50.2798332832896]]]},"properties":{"name":"Small Square WA27 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65006907472082,50.3246041327566]},"properties":{"name":"WA27"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72003529856692,50.3697548316587],[-2.71950539716368,50.4596659883699],[-2.57866091634103,50.4592414066979],[-2.57945713218402,50.3693315954956],[-2.72003529856692,50.3697548316587]]]},"properties":{"name":"Small Square WA28 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.6494076163507,50.4145243769473]},"properties":{"name":"WA28"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.71950534403337,50.4596749803148],[-2.71897273967126,50.5495847383157],[-2.57786055945863,50.549158805915],[-2.57866083650885,50.459250398508],[-2.71950534403337,50.4596749803148]]]},"properties":{"name":"Small Square WA29 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.64874278668226,50.504443219575]},"properties":{"name":"WA29"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.5856706034292,49.6499304836276],[-2.58490590434184,49.7398515537156],[-2.44615871686239,49.7392714110372],[-2.4471791562095,49.649352171451],[-2.5856706034292,49.6499304836276]]]},"properties":{"name":"Small Square WA30 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51597161863907,49.6946267868908]},"properties":{"name":"WA30"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58490582767203,49.7398605466514],[-2.58413727555979,49.8297802066931],[-2.44513303382162,49.8291982265883],[-2.44615861455171,49.7392804037895],[-2.58490582767203,49.7398605466514]]]},"properties":{"name":"Small Square WA31 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51507669828192,49.7845552932818]},"properties":{"name":"WA31"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58413719850338,49.8297891994879],[-2.58336476814429,49.9197074502184],[-2.44410217522798,49.9191236258985],[-2.44513293099508,49.829207219199],[-2.58413719850338,49.8297891994879]]]},"properties":{"name":"Small Square WA32 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51417726548449,49.8744823867108]},"properties":{"name":"WA32"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58336469069875,49.9197164428723],[-2.5825883566424,50.0096332850401],[-2.44306610711926,50.0090476096693],[-2.44410207188219,49.9191326183677],[-2.58336469069875,49.9197164428723]]]},"properties":{"name":"Small Square WA33 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51327329067207,49.9644080678978]},"properties":{"name":"WA33"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58258827880517,50.0096422775531],[-2.58180801537011,50.0995577119197],[-2.442024795225,50.0989701786145],[-2.44306600325081,50.0090566019969],[-2.58258827880517,50.0096422775531]]]},"properties":{"name":"Small Square WA34 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51236474400181,50.0543323375758]},"properties":{"name":"WA34"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58180793713861,50.099566704292],[-2.58102371840982,50.1894807316321],[-2.44097820496303,50.188891333461],[-2.44202469083045,50.0989791708007],[-2.58180793713861,50.099566704292]]]},"properties":{"name":"Small Square WA35 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51145159535969,50.144255196491]},"properties":{"name":"WA35"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58102363978145,50.1894897238638],[-2.58023543960767,50.2794023449654],[-2.43992630143595,50.2788110749483],[-2.4409781000389,50.1889003255058],[-2.58102363978145,50.1894897238638]]]},"properties":{"name":"Small Square WA36 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51053381435748,50.2341766454022]},"properties":{"name":"WA36"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.5802353605798,50.2794113370564],[-2.57944315257084,50.3693225527205],[-2.43886904942758,50.3687294038285],[-2.43992619597874,50.2788200668518],[-2.5802353605798,50.2794113370564]]]},"properties":{"name":"Small Square WA37 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.50961137032966,50.3240966850814]},"properties":{"name":"WA37"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.57944307314082,50.369331544671],[-2.57864683066492,50.4592413557118],[-2.43780641339935,50.4586463208667],[-2.43886894343375,50.3687383955908],[-2.57944307314082,50.369331544671]]]},"properties":{"name":"Small Square WA38 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.50868423233026,50.4140153163135]},"properties":{"name":"WA38"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.57864675083007,50.4592503475219],[-2.57784644701111,50.5491587547666],[-2.43673835748666,50.5485618268402],[-2.43780630686533,50.4586553124878],[-2.57864675083007,50.4592503475219]]]},"properties":{"name":"Small Square WA39 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.50775236912971,50.5039325398964]},"properties":{"name":"WA39"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44716530591393,49.6493521053304],[-2.44614484099176,49.7392713447073],[-2.3074027971653,49.7385250283383],[-2.30867896898982,49.6486081438063],[-2.44716530591393,49.6493521053304]]]},"properties":{"name":"Small Square WA40 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.3773409891602,49.6939645281846]},"properties":{"name":"WA40"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44614473867852,49.7392803374597],[-2.44511913224454,49.8291981600483],[-2.30612006782156,49.8284494799263],[-2.30740266921454,49.7385340208547],[-2.44614473867852,49.7392803374597]]]},"properties":{"name":"Small Square WA41 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37618964977433,49.7838909375984]},"properties":{"name":"WA41"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44511902941542,49.829207152659],[-2.44408824781476,49.9191235591478],[-2.30483086618068,49.9183725065396],[-2.30611993922568,49.8284584723002],[-2.44511902941542,49.829207152659]]]},"properties":{"name":"Small Square WA42 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37503250526668,49.873815926315]},"properties":{"name":"WA42"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44408814446638,49.9191325516169],[-2.44305215373935,50.0090475427069],[-2.30353514977378,50.0082941088187],[-2.30483073693546,49.9183814987711],[-2.44408814446638,49.9191325516169]]]},"properties":{"name":"Small Square WA43 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37386951759233,49.9637394950008]},"properties":{"name":"WA43"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.4430520498683,50.0090565350345],[-2.44201081574701,50.0989701114397],[-2.30223287574652,50.0982142874163],[-2.30353501987494,50.0083031009077],[-2.4430520498683,50.0090565350345]]]},"properties":{"name":"Small Square WA44 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37270064836141,50.0536616443346]},"properties":{"name":"WA44"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44201071134984,50.0989791036259],[-2.44096419925468,50.188891266073],[-2.30092400085482,50.1881330429973],[-2.30223274518977,50.098223279363],[-2.44201071134984,50.0989791036259]]]},"properties":{"name":"Small Square WA45 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37152585883526,50.1435823750078]},"properties":{"name":"WA45"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44096409432792,50.1889002581178],[-2.43991226936411,50.2788110073462],[-2.29960848146043,50.278050376239],[-2.3009238696358,50.1881420348018],[-2.44096409432792,50.1889002581178]]]},"properties":{"name":"Small Square WA46 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.3703451099225,50.2335016877241]},"properties":{"name":"WA46"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.43991216390425,50.2788199992497],[-2.43885499085822,50.3687293360116],[-2.29828627352653,50.3679662878307],[-2.29960834957477,50.2780593679013],[-2.43991216390425,50.2788199992497]]]},"properties":{"name":"Small Square WA47 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.36915836217506,50.3234195831999]},"properties":{"name":"WA47"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.43885488486173,50.3687383277739],[-2.43779232819756,50.4586462528341],[-2.29695733261316,50.4578807784736],[-2.2982861409698,50.3679752793508],[-2.43885488486173,50.3687383277739]]]},"properties":{"name":"Small Square WA48 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.36796557578413,50.4133360621639]},"properties":{"name":"WA48"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.43779222166087,50.4586552444553],[-2.43672424551662,50.5485617585913],[-2.29562161387271,50.5477938488814],[-2.29695719938089,50.4578897698517],[-2.43779222166087,50.4586552444553]]]},"properties":{"name":"Small Square WA49 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.36676671057609,50.5032511253572]},"properties":{"name":"WA49"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30866511926934,49.6486080611199],[-2.30738892187351,49.7385249453902],[-2.16865330987383,49.7376124720616],[-2.17018517246154,49.6476984668785],[-2.30866511926934,49.6486080611199]]]},"properties":{"name":"Small Square WA50 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23871612929729,49.6931363494588]},"properties":{"name":"WA50"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30738879392019,49.7385339379066],[-2.30610616682711,49.8284493967155],[-2.16711357632247,49.827534033409],[-2.16865315628718,49.7376214642896],[-2.30738879392019,49.7385339379066]]]},"properties":{"name":"Small Square WA51 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23730840859419,49.783060136531]},"properties":{"name":"WA51"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30610603822865,49.8284583890894],[-2.30481693935391,49.9183724230651],[-2.16556607411094,49.9174541591038],[-2.16711342196149,49.8275430254933],[-2.30610603822865,49.8284583890894]]]},"properties":{"name":"Small Square WA52 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23589359042898,49.8729824932333]},"properties":{"name":"WA52"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.3048168101061,49.9183814152965],[-2.30352119698418,50.0082940250795],[-2.1640107522679,50.0073728497123],[-2.16556591897055,49.9174631510446],[-2.3048168101061,49.9183814152965]]]},"properties":{"name":"Small Square WA53 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23447162829033,49.962903420165]},"properties":{"name":"WA53"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30352106708274,50.0083030171685],[-2.30221889686272,50.0982142034115],[-2.1624475593595,50.0972901058123],[-2.16401059634299,50.0073818415096],[-2.30352106708274,50.0083030171685]]]},"properties":{"name":"Small Square WA54 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23304247524523,50.052822917937]},"properties":{"name":"WA54"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30221876630335,50.0982231953581],[-2.30090999574459,50.1881329587259],[-2.16087644348413,50.1872059279933],[-2.16244740264489,50.0972990974662],[-2.30221876630335,50.0982231953581]]]},"properties":{"name":"Small Square WA55 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23160608393429,50.1427409871723]},"properties":{"name":"WA55"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30090986452295,50.1881419505303],[-2.29959444999068,50.2780502917],[-2.15929735226714,50.2771203168561],[-2.16087628597461,50.1872149195038],[-2.30090986452295,50.1881419505303]]]},"properties":{"name":"Small Square WA56 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.23016240656698,50.2326576285057]},"properties":{"name":"WA56"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.29959431810237,50.2780592833622],[-2.29827221556325,50.367966203023],[-2.15771023285557,50.3670332730133],[-2.15929719395746,50.2771293082234],[-2.29959431810237,50.2780592833622]]]},"properties":{"name":"Small Square WA57 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.22871139491669,50.3225728425839]},"properties":{"name":"WA57"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.29827208300386,50.367975194543],[-2.29694324802149,50.4578806933963],[-2.15611503191266,50.4569447970884],[-2.1577100737404,50.3670422642372],[-2.29827208300386,50.367975194543]]]},"properties":{"name":"Small Square WA58 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.22725300031586,50.4124866300653]},"properties":{"name":"WA58"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.29694311478656,50.4578896847743],[-2.29560750251687,50.5477937635334],[-2.15451169561241,50.5468548897168],[-2.15611487198665,50.4569537881692],[-2.29694311478656,50.4578896847743]]]},"properties":{"name":"Small Square WA59 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.22578717365099,50.5023989916203]},"properties":{"name":"WA59"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.17017132344411,49.6476983676282],[-2.16863943528969,49.7376123724971],[-2.02991154291374,49.7365337626627],[-2.03169904620065,49.6466231610001],[-2.17017132344411,49.6476983676282]]]},"properties":{"name":"Small Square WA60 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10009832298898,49.6921422692519]},"properties":{"name":"WA60"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16863928170048,49.737621364725],[-2.1670996760403,49.8275339335292],[-2.02811485567615,49.826451907616],[-2.02991136369623,49.7365427545496],[-2.16863928170048,49.737621364725]]]},"properties":{"name":"Small Square WA61 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.09843426707056,49.7820629087307]},"properties":{"name":"WA61"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16709952167675,49.8275429256135],[-2.16555214800112,49.9174540589074],[-2.0263091038728,49.916368604296],[-2.02811467555514,49.8264608993581],[-2.16709952167675,49.8275429256135]]]},"properties":{"name":"Small Square WA62 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.09676182176673,49.8719821062302]},"properties":{"name":"WA62"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16555199285814,49.9174630508482],[-2.16399680019997,50.0073727491983],[-2.02449422803508,50.0062838531813],[-2.02630892284237,49.9163775958933],[-2.16555199285814,49.9174630508482]]]},"properties":{"name":"Small Square WA63 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.09508093210439,49.961899862269]},"properties":{"name":"WA63"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16399664427245,50.0073817409955],[-2.16243358120213,50.0972900049794],[-2.02267016815479,50.0961976547613],[-2.02449404608926,50.0062928446339],[-2.16399664427245,50.0073817409955]]]},"properties":{"name":"Small Square WA64 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.09339154261217,50.0518161773768]},"properties":{"name":"WA64"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16243342448491,50.0972989966333],[-2.16086243910513,50.1872058268404],[-2.02083686367805,50.186110009536],[-2.02266998528754,50.0962066460691],[-2.16243342448491,50.0972989966333]]]},"properties":{"name":"Small Square WA65 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.09169359731473,50.1417310520945]},"properties":{"name":"WA65"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.16086228159298,50.1872148183509],[-2.15928332153346,50.277120215382],[-2.01899425349918,50.2760209180162],[-2.02083667988329,50.1861190006991],[-2.16086228159298,50.1872148183509]]]},"properties":{"name":"Small Square WA66 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.08998703972723,50.2316444869742]},"properties":{"name":"WA66"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.15928316322113,50.2771292067492],[-2.15769617563326,50.3670331712167],[-2.01714227595446,50.3659303807235],[-2.01899406877078,50.2760299090348],[-2.15928316322113,50.2771292067492]]]},"properties":{"name":"Small Square WA67 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.08827181284947,50.3215564825788]},"properties":{"name":"WA67"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.15769601651544,50.3670421624406],[-2.15610094806688,50.4569446949682],[-2.01528086881582,50.4558383981898],[-2.01714209028622,50.3659393715974],[-2.15769601651544,50.3670421624406]]]},"properties":{"name":"Small Square WA68 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.08654785916014,50.4114670394826]},"properties":{"name":"WA68"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.15610078813822,50.4569536860489],[-2.15449758500745,50.5468547872717],[-2.01340996928444,50.5457449709579],[-2.01528068220149,50.4558473889193],[-2.15610078813822,50.4569536860489]]]},"properties":{"name":"Small Square WA69 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.08481512061088,50.5013761582709]},"properties":{"name":"WA69"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02989748994595,49.7365426383709],[-2.02810095623588,49.8264517910694],[-1.88912520177708,49.8252031268712],[-1.89117857891606,49.7352979158119],[-2.02989748994595,49.7365426383709]]]},"properties":{"name":"Small Square WA71 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.95956851711562,49.7808992765818]},"properties":{"name":"WA71"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02810077611229,49.8264607828114],[-2.0262951786104,49.9163684873801],[-1.88706125985791,49.9151158665883],[-1.88912499590196,49.8252121182183],[-2.02810077611229,49.8264607828114]]]},"properties":{"name":"Small Square WA72 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.9576384996537,49.8708147878261]},"properties":{"name":"WA72"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02629499757738,49.9163774789774],[-2.02448027682014,50.0062837358948],[-1.88498689004116,50.0050271438471],[-1.88706105294341,49.9151248577891],[-2.02629499757738,49.9163774789774]]]},"properties":{"name":"Small Square WA73 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.95569873794658,49.9607288439707]},"properties":{"name":"WA73"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02448009487171,50.0062927273472],[-2.02265619085603,50.0961975371027],[-1.88290202375034,50.0949369590349],[-1.88498668208045,50.0050361349017],[-2.02448009487171,50.0062927273472]]]},"properties":{"name":"Small Square WA74 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.95374916799007,50.0506414454504]},"properties":{"name":"WA74"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02265600798617,50.0962065284104],[-2.02082286016334,50.1861098915039],[-1.88080659178545,50.1848453125488],[-1.88290181473653,50.0949459499434],[-2.02265600798617,50.0962065284104]]]},"properties":{"name":"Small Square WA75 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.95178972519859,50.1405525927103]},"properties":{"name":"WA75"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.02082267636596,50.186118882667],[-2.01898022363551,50.2760207996093],[-1.87870052431599,50.2747522047957],[-1.88080638171159,50.1848543033111],[-2.02082267636596,50.186118882667]]]},"properties":{"name":"Small Square WA76 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.94982034439871,50.2304622862059]},"properties":{"name":"WA76"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.01898003890447,50.2760297906278],[-2.01712821960794,50.3659302619403],[-1.87658375087382,50.364657636192],[-1.87870031317507,50.2747611954118],[-2.01898003890447,50.2760297906278]]]},"properties":{"name":"Small Square WA77 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.94784095982248,50.3203705264029]},"properties":{"name":"WA77"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.01712803393705,50.3659392528143],[-2.01526678585167,50.455838279029],[-1.87445620034594,50.4545616071642],[-1.87658353865875,50.3646666266621],[-2.01712803393705,50.3659392528143]]]},"properties":{"name":"Small Square WA78 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.94585150510072,50.410277313777]},"properties":{"name":"WA78"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.01526659923467,50.4558472697585],[-2.013395859567,50.545744851418],[-1.87231780096721,50.5444641181481],[-1.87445598704959,50.4545705974883],[-2.01526659923467,50.4558472697585]]]},"properties":{"name":"Small Square WA79 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.94385191325622,50.5001826488144]},"properties":{"name":"WA79"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.0011779280519,48.7512701782748],[-3.00118051285359,48.8412076482802],[-2.86492713640833,48.8411286195089],[-2.86516790151575,48.7511913974918],[-3.0011779280519,48.7512701782748]]]},"properties":{"name":"Small Square WV00 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93310655621939,48.7962242270388]},"properties":{"name":"WV00"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00118051311272,48.8412166428562],[-3.00118311056115,48.9311527042555],[-2.86468515134806,48.9310734265883],[-2.86492711226975,48.8411376140601],[-3.00118051311272,48.8412166428562]]]},"properties":{"name":"Small Square WV01 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93298714610424,48.8861699262773]},"properties":{"name":"WV01"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00118311082155,48.9311616986907],[-3.00118572099767,49.021096352141],[-2.86444196271694,49.0210168246892],[-2.8646851270895,48.9310824209986],[-3.00118311082155,48.9311616986907]]]},"properties":{"name":"Small Square WV02 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93286714239625,48.9761142168792]},"properties":{"name":"WV02"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00118572125935,49.0211053464354],[-3.00118834424483,49.1110385926079],[-2.86419756280984,49.1109588144767],[-2.86444193833763,49.0210258189586],[-3.00118572125935,49.0211053464354]]]},"properties":{"name":"Small Square WV03 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93274654130004,49.0660570995071]},"properties":{"name":"WV03"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.0011883445078,49.1110475867616],[-3.00119098038505,49.2009794263411],[-2.86395194385316,49.2008993966294],[-2.86419753830902,49.1109678086052],[-3.0011883445078,49.1110475867616]]]},"properties":{"name":"Small Square WV04 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93262533898657,49.1559985748376]},"properties":{"name":"WV04"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00119098064931,49.2009884203541],[-3.00119362950145,49.2909188540393],[-2.86370509800407,49.2908385718401],[-2.86395191923005,49.2009083906173],[-3.00119098064931,49.2009884203541]]]},"properties":{"name":"Small Square WV05 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93250353159272,49.2459386435612]},"properties":{"name":"WV05"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00119362976702,49.2909278479118],[-3.00119629167793,49.3808568764151],[-2.86345701734973,49.380776340815],[-2.86370507325788,49.2908475656873],[-3.00119362976702,49.2909278479118]]]},"properties":{"name":"Small Square WV06 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93238111522092,49.3358773063818]},"properties":{"name":"WV06"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.0011962919448,49.3808658701471],[-3.0011989669991,49.4707934941949],[-2.86320769390651,49.4707127042742],[-2.86345699247965,49.3807853345216],[-3.0011962919448,49.3808658701471]]]},"properties":{"name":"Small Square WV07 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93225808593878,49.4258145640174]},"properties":{"name":"WV07"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00119896726729,49.4708024877865],[-3.00120165555037,49.5607287081188],[-2.86295711961925,49.5606476629515],[-2.86320766891175,49.4707216978403],[-3.00119896726729,49.4708024877865]]]},"properties":{"name":"Small Square WV08 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93213443977869,49.5157504171997]},"properties":{"name":"WV08"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-3.00120165581989,49.5607377015701],[-3.00120435741788,49.6506625189407],[-2.86270528636044,49.6505812175944],[-2.86295709449901,49.5606566563771],[-3.00120165581989,49.5607377015701]]]},"properties":{"name":"Small Square WV09 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.93201017273747,49.6056848666742]},"properties":{"name":"WV09"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86515429919237,48.7511913815854],[-2.86491350974778,48.8411286035523],[-2.72866133133956,48.8408885340685],[-2.72914546311642,48.7509520659897],[-2.86515429919237,48.7511913815854]]]},"properties":{"name":"Small Square WV10 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79696182525013,48.7960649041724]},"properties":{"name":"WV10"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86491348560676,48.8411375981035],[-2.86467150022705,48.9310734105815],[-2.72817474669562,48.9308325844468],[-2.72866128280156,48.8408975285442],[-2.86491348560676,48.8411375981035]]]},"properties":{"name":"Small Square WV11 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79659841594311,48.8860101014533]},"properties":{"name":"WV11"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86467147596603,48.9310824049917],[-2.86442828701381,49.0210168086319],[-2.72768574212716,49.0207752231406],[-2.7281746979164,48.9308415787813],[-2.86467147596603,48.9310824049917]]]},"properties":{"name":"Small Square WV12 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79623320051428,48.9759538883061]},"properties":{"name":"WV12"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86442826263204,49.0210258029013],[-2.86418386240218,49.1109587983687],[-2.72719430214222,49.1107164507966],[-2.72768569310518,49.0207842173339],[-2.86442826263204,49.0210258029013]]]},"properties":{"name":"Small Square WV13 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.7958661674153,49.0658962653813]},"properties":{"name":"WV13"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86418383789889,49.1109677924973],[-2.86393821861778,49.2008993804706],[-2.72670041111117,49.2006562680749],[-2.72719425287592,49.1107254448488],[-2.86418383789889,49.1109677924973]]]},"properties":{"name":"Small Square WV14 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.7954973049953,49.1558372333432]},"properties":{"name":"WV14"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86393819399217,49.2009083744585],[-2.86369134781696,49.2908385556303],[-2.72620405326515,49.2905946756493],[-2.72670036159898,49.2006652619861],[-2.86393819399217,49.2009083744585]]]},"properties":{"name":"Small Square WV15 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79512660149975,49.2457767928696]},"properties":{"name":"WV15"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86369132306826,49.2908475494775],[-2.86344324208609,49.380776324554],[-2.72570521269458,49.3805316742071],[-2.72620400350549,49.2906036694196],[-2.86369132306826,49.2908475494775]]]},"properties":{"name":"Small Square WV16 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79475404506931,49.3357149446521]},"properties":{"name":"WV16"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86344321721349,49.3807853182606],[-2.86319389344074,49.4707126879618],[-2.72520387334756,49.4704672644494],[-2.72570516268584,49.3805406678366],[-2.86344321721349,49.3807853182606]]]},"properties":{"name":"Small Square WV17 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79437962373869,49.425651689396]},"properties":{"name":"WV17"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86319386844346,49.4707216815279],[-2.86294329382493,49.5606476465876],[-2.72470001902836,49.5604014470907],[-2.72520382308814,49.4704762579381],[-2.86319386844346,49.4707216815279]]]},"properties":{"name":"Small Square WV18 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79400332543545,49.5155870278203]},"properties":{"name":"WV18"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.86294326870215,49.5606566400132],[-2.86269143511033,49.6505812011787],[-2.72419363339575,49.6503342228589],[-2.72469996851662,49.5604104404386],[-2.86294326870215,49.5606566400132]]]},"properties":{"name":"Small Square WV19 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.79362513797886,49.6055209606575]},"properties":{"name":"WV19"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72913186097215,48.7509520340284],[-2.72864770485925,48.8408885020065],[-2.59239793299232,48.8404873970442],[-2.59312541621166,48.7505521888233],[-2.72913186097215,48.7509520340284]]]},"properties":{"name":"Small Square WV20 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.66081889110986,48.7957447798349]},"properties":{"name":"WV20"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72864765631882,48.8408974964821],[-2.728161095756,48.9308325522837],[-2.59166676412798,48.9304301829466],[-2.59239786005645,48.8404963913936],[-2.72864765631882,48.8408974964821]]]},"properties":{"name":"Small Square WV21 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.66021149406542,48.8856889682691]},"properties":{"name":"WV21"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72816104697433,48.9308415466181],[-2.72767206660659,49.0207751908761],[-2.59093195912171,49.0203715526418],[-2.59166669082966,48.9304391771544],[-2.72816104697433,48.9308415466181]]]},"properties":{"name":"Small Square WV22 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65960107847169,48.9756317426729]},"properties":{"name":"WV22"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72767201758214,49.0207841850694],[-2.7271806019183,49.1107164184303],[-2.5901934946962,49.1103115067454],[-2.59093188545861,49.0203805467079],[-2.72767201758214,49.0207841850694]]]},"properties":{"name":"Small Square WV23 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65898762502846,49.0655731036721]},"properties":{"name":"WV23"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72718055264952,49.1107254124825],[-2.7266866860607,49.2006562356064],[-2.5894513473673,49.2002500458865],[-2.59019342066599,49.11032050067],[-2.72718055264952,49.1107254124825]]]},"properties":{"name":"Small Square WV24 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65837111426417,49.1555130519063]},"properties":{"name":"WV24"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72668663654602,49.2006652295176],[-2.72619030326414,49.2905946430783],[-2.58870549344166,49.2901871707075],[-2.58945127296761,49.2002590396697],[-2.72668663654602,49.2006652295176]]]},"properties":{"name":"Small Square WV25 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65775152653402,49.2454515880284]},"properties":{"name":"WV25"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72619025350197,49.2906036368486],[-2.72569143761824,49.3805316415333],[-2.58795590901451,49.3801228818642],[-2.58870541867012,49.2901961643493],[-2.72619025350197,49.2906036368486]]]},"properties":{"name":"Small Square WV26 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65712884201804,49.3353887127048]},"properties":{"name":"WV26"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72569138760699,49.3805406351627],[-2.72519007307031,49.4704672316723],[-2.58720256996727,49.4700571800254],[-2.58795583386872,49.3801318753646],[-2.72569138760699,49.3805406351627]]]},"properties":{"name":"Small Square WV27 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65650304071923,49.4253244266152]},"properties":{"name":"WV27"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72519002280836,49.4704762251609],[-2.72468619342378,49.5604014142099],[-2.5864454519652,49.5599900658735],[-2.5872024944448,49.4700661733846],[-2.72519002280836,49.4704762251609]]]},"properties":{"name":"Small Square WV28 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65587410246149,49.5152587304531]},"properties":{"name":"WV28"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.72468614290951,49.5604104075578],[-2.72417978233662,49.6503341898741],[-2.58568453045502,49.649921540104],[-2.58644537606361,49.5599990590915],[-2.72468614290951,49.5604104075578]]]},"properties":{"name":"Small Square WV29 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.65524200688777,49.6051916249251]},"properties":{"name":"WV29"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.59311181436659,48.7505521408077],[-2.59238430681312,48.8404873488774],[-2.456138149857,48.8399252171798],[-2.45710896164352,48.7499917746849],[-2.59311181436659,48.7505521408077]]]},"properties":{"name":"Small Square WV30 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.52467895853217,48.7952638609953]},"properties":{"name":"WV30"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.59238423387482,48.8404963432268],[-2.59165311349139,48.9304301346279],[-2.45516241985231,48.9298662308836],[-2.45613805252555,48.8399342113523],[-2.59238423387482,48.8404963432268]]]},"properties":{"name":"Small Square WV31 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.52382759288844,48.885206533735]},"properties":{"name":"WV31"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.59165304019061,48.9304391288357],[-2.5909182839061,49.0203715041707],[-2.45418183769296,49.0198058220409],[-2.45516232203719,48.9298752249138],[-2.59165304019061,48.9304391288357]]]},"properties":{"name":"Small Square WV32 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.5229719964375,48.9751477870314]},"properties":{"name":"WV32"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.59091821024054,49.0203804982369],[-2.5901797947792,49.1103114581214],[-2.45319637231855,49.109743991224],[-2.45418173939108,49.0198148159289],[-2.59091821024054,49.0203804982369]]]},"properties":{"name":"Small Square WV33 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.52211214212912,49.0650876214734]},"properties":{"name":"WV33"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.59017972074651,49.110320452046],[-2.58943762262572,49.200249997109],[-2.45220599239267,49.1996807390186],[-2.45319627352679,49.1097529849699],[-2.59017972074651,49.110320452046]]]},"properties":{"name":"Small Square WV34 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.52124800267293,49.1550260376635]},"properties":{"name":"WV34"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58943754822354,49.2002589908922],[-2.58869174375154,49.2901871217761],[-2.4512106662998,49.2896160660229],[-2.45220589310787,49.1996897326223],[-2.58943754822354,49.2002589908922]]]},"properties":{"name":"Small Square WV35 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.52037955053575,49.2449630362168]},"properties":{"name":"WV35"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.5886916689775,49.2901961154178],[-2.58794213425107,49.3801228327781],[-2.45021036214229,49.3795499728482],[-2.45121056651879,49.2896250594845],[-2.5886916689775,49.2901961154178]]]},"properties":{"name":"Small Square WV36 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51950675793896,49.3348986177621]},"properties":{"name":"WV36"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58794205910277,49.3801318262785],[-2.58718877000494,49.4700571307842],[-2.44920504773725,49.4694824601187],[-2.45021026186188,49.3795589661679],[-2.58794205910277,49.3801318262785]]]},"properties":{"name":"Small Square WV37 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51862959685575,49.4248327829408]},"properties":{"name":"WV37"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58718869447995,49.4700661241434],[-2.58643162667759,49.5599900164766],[-2.44819469061335,49.5594135284716],[-2.4492049469542,49.4694914532965],[-2.58718869447995,49.4700661241434]]]},"properties":{"name":"Small Square WV38 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51774803900839,49.5147655324077]},"properties":{"name":"WV38"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.58643155077347,49.5599990096946],[-2.58567067971493,49.6499214905508],[-2.44717925800766,49.6493431785568],[-2.44819458932439,49.5594225215076],[-2.58643155077347,49.5599990096946]]]},"properties":{"name":"Small Square WV39 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.51686205586546,49.6046968668308]},"properties":{"name":"WV39"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45709536021772,48.7499917106162],[-2.45612452409975,48.8399251529093],[-2.31988319022153,48.8392020067282],[-2.32109730005379,48.749270835755],[-2.45709536021772,48.7499917106162]]]},"properties":{"name":"Small Square WV40 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38854323208295,48.7946221581214]},"properties":{"name":"WV40"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45612442676586,48.8399341470818],[-2.45514876964036,48.9298661664104],[-2.31866292987112,48.9291407405834],[-2.31988306849758,48.8392110006731],[-2.45612442676586,48.8399341470818]]]},"properties":{"name":"Small Square WV41 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38744792465992,48.8845628083809]},"properties":{"name":"WV41"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45514867182279,48.9298751604407],[-2.45416816290471,49.0198057573644],[-2.3174366016264,49.0190780437369],[-2.3186628075423,48.9291497343852],[-2.45514867182279,48.9298751604407]]]},"properties":{"name":"Small Square WV42 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38634717440934,48.9745020319742]},"properties":{"name":"WV42"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45416806460037,49.0198147512523],[-2.45318267283165,49.1097439263435],[-2.3162041666469,49.1090139167056],[-2.31743647868886,49.0190870373957],[-2.45416806460037,49.0198147512523]]]},"properties":{"name":"Small Square WV43 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.3852409465336,49.064439829441]},"properties":{"name":"WV43"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45318257403741,49.1097529200893],[-2.45219226808395,49.1996806739332],[-2.31496558574696,49.1989483600187],[-2.31620404309673,49.1090229102214],[-2.45318257403741,49.1097529200893]]]},"properties":{"name":"Small Square WV44 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38412920592614,49.154376201334]},"properties":{"name":"WV44"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45219216879667,49.1996896675369],[-2.45119691704533,49.289616000732],[-2.31372081939197,49.288881374218],[-2.31496546158023,49.1989573533916],[-2.45219216879667,49.1996896675369]]]},"properties":{"name":"Small Square WV45 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38301191716809,49.2443111482184]},"properties":{"name":"WV45"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.45119681726182,49.2896249941936],[-2.45019658781733,49.379549907351],[-2.31246982769455,49.3788129598578],[-2.31372069460471,49.288890367448],[-2.45119681726182,49.2896249941936]]]},"properties":{"name":"Small Square WV46 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38188904452485,49.3342446706722]},"properties":{"name":"WV46"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.4501964875344,49.3795589006707],[-2.44919124821624,49.4694823944145],[-2.3112125704106,49.4687431175045],[-2.31246970228274,49.3788219529449],[-2.4501964875344,49.3795589006707]]]},"properties":{"name":"Small Square WV47 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.38076055194256,49.4241767692861]},"properties":{"name":"WV47"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44919114743066,49.4694913875923],[-2.44818086576993,49.5594134625597],[-2.30994900693541,49.5586718477372],[-2.31121244437021,49.4687521104489],[-2.44919114743066,49.4694913875923]]]},"properties":{"name":"Small Square WV48 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37962640304463,49.5141074446634]},"properties":{"name":"WV48"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.44818076447843,49.5594224555956],[-2.44716540771464,49.6493431124363],[-2.30867909629965,49.6485991511472],[-2.30994888026236,49.5586808405389],[-2.44818076447843,49.5594224555956]]]},"properties":{"name":"Small Square WV49 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.37848656112814,49.6040366974201]},"properties":{"name":"WV49"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.32108369916732,48.7492707556345],[-2.31986956500704,48.8392019263553],[-2.18363426210382,48.8383177814499],[-2.18509163181715,48.7483893877014],[-2.32108369916732,48.7492707556345]]]},"properties":{"name":"Small Square WV50 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.25241291609315,48.7938196851789]},"properties":{"name":"WV50"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31986944328065,48.8392109203002],[-2.31864928020539,48.9291406599571],[-2.18216950991391,48.9282537279003],[-2.18363411599119,48.8383267751166],[-2.31986944328065,48.8392109203002]]]},"properties":{"name":"Small Square WV51 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.25107370139005,48.8837578062556]},"properties":{"name":"WV51"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31864915787413,48.9291496537589],[-2.31742292738788,49.0190779628564],[-2.18069747443154,49.0181882336788],[-2.18216936307527,48.9282627214229],[-2.31864915787413,48.9291496537589]]]},"properties":{"name":"Small Square WV52 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24972783214472,48.9736944916337]},"properties":{"name":"WV52"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31742280444788,49.0190869565152],[-2.31619046771325,49.1090138355699],[-2.17921810903985,49.108121299234],[-2.18069732686224,49.0181972270573],[-2.31742280444788,49.0190869565152]]]},"properties":{"name":"Small Square WV53 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24837526581545,49.0636297417915]},"properties":{"name":"WV53"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31619034416061,49.1090228290856],[-2.31495186199506,49.1989482786269],[-2.17773136670775,49.1980529250269],[-2.17921796073521,49.1081302924686],[-2.31619034416061,49.1090228290856]]]},"properties":{"name":"Small Square WV54 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24701595948293,49.1535635572195]},"properties":{"name":"WV54"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31495173782583,49.1989572719997],[-2.3137070706979,49.2888812925692],[-2.17623719998539,49.2879831115298],[-2.17773121766305,49.1980619181175],[-2.31495173782583,49.1989572719997]]]},"properties":{"name":"Small Square WV55 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24564986984601,49.2434959384204]},"properties":{"name":"WV55"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31370694590814,49.2888902857991],[-2.3124560539336,49.3788128779509],[-2.17473556099951,49.3779118592272],[-2.17623705019587,49.2879921044765],[-2.31370694590814,49.2888902857991]]]},"properties":{"name":"Small Square WV56 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24427695321758,49.3334268859088]},"properties":{"name":"WV56"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31245592851928,49.3788218710381],[-2.31119877145726,49.4687430353388],[-2.1732264014488,49.4678391686153],[-2.17473541046035,49.37792085203],[-2.31245592851928,49.3788218710381]]]},"properties":{"name":"Small Square WV57 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24289716552031,49.4233564002118]},"properties":{"name":"WV57"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.31119864541434,49.4687520282831],[-2.30993518266335,49.5586717653117],[-2.17170967259916,49.557765040202],[-2.17322625015516,49.4678481612743],[-2.31119864541434,49.4687520282831]]]},"properties":{"name":"Small Square WV58 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24151046228227,49.5132844818684]},"properties":{"name":"WV58"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.30993505598776,49.5586807581133],[-2.30866524658172,49.6485990684609],[-2.17018532527888,49.6476894745069],[-2.17170952054613,49.5577740327173],[-2.30993505598776,49.5586807581133]]]},"properties":{"name":"Small Square WV59 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.24011679863265,49.6032111314297]},"properties":{"name":"WV59"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.18507803159004,48.7483892915309],[-2.18362063755288,48.8383176849764],[-2.04739257318412,48.8372725606126],[-2.04909315697429,48.7473474496781],[-2.18507803159004,48.7483892915309]]]},"properties":{"name":"Small Square WV60 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.11628921459149,48.7928564596309]},"properties":{"name":"WV60"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.18362049143781,48.8383266786431],[-2.18215586091597,48.9282536311227],[-2.04568337536888,48.9272052122165],[-2.04739240268741,48.8372815539504],[-2.18362049143781,48.8383266786431]]]},"properties":{"name":"Small Square WV61 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.11470613478354,48.8827915449256]},"properties":{"name":"WV61"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.18215571407488,48.9282626246453],[-2.18068380086508,49.018188136596],[-2.04396567927278,49.0171364113639],[-2.04568320402504,48.9272142054091],[-2.18215571407488,48.9282626246453]]]},"properties":{"name":"Small Square WV62 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.11311518909226,48.9727251836811]},"properties":{"name":"WV62"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.18068365329331,49.0181971299745],[-2.17920441078256,49.108121201845],[-2.04223943050711,49.1070661584234],[-2.04396550707641,49.0171454044113],[-2.18068365329331,49.0181971299745]]]},"properties":{"name":"Small Square WV63 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.11151632723599,49.0626573763014]},"properties":{"name":"WV63"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.17920426247545,49.1081301950795],[-2.17771764363656,49.1980528273304],[-2.0405045741999,49.1969944537743],[-2.04223925745273,49.1070751513255],[-2.17920426247545,49.1081301950795]]]},"properties":{"name":"Small Square WV64 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10990949848674,49.1525881232027]},"properties":{"name":"WV64"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.17771749458938,49.198061820421],[-2.17622345197643,49.2879830135248],[-2.03876105499063,49.2869212978077],[-2.04050440028201,49.1970034465313],[-2.17771749458938,49.198061820421]]]},"properties":{"name":"Small Square WV65 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10829465166532,49.2425174248124]},"properties":{"name":"WV65"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.1762233021844,49.2879920064715],[-2.1747217879281,49.3779117609126],[-2.03700881702488,49.3768466909253],[-2.03876088020367,49.2869302904195],[-2.1762233021844,49.2879920064715]]]},"properties":{"name":"Small Square WV66 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10667173513637,49.3324452815695]},"properties":{"name":"WV66"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.17472163738643,49.3779207537154],[-2.17321260318947,49.4678390699899],[-2.03524780394883,49.4667706335401],[-2.03700864136323,49.3768556833921],[-2.17472163738643,49.3779207537154]]]},"properties":{"name":"Small Square WV67 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10504069680335,49.4223716939245]},"properties":{"name":"WV67"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.1732124518933,49.4678480626489],[-2.17169584902561,49.5577649412647],[-2.03347795890378,49.5566931260761],[-2.03524762740683,49.4667796258618],[-2.1732124518933,49.4678480626489]]]},"properties":{"name":"Small Square WV68 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10340148410342,49.5122966623391]},"properties":{"name":"WV68"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.17169569697005,49.5577739337799],[-2.17017147626401,49.6476893752567],[-2.03169922452053,49.6466141689683],[-2.03347778147572,49.5567021182529],[-2.17169569697005,49.5577739337799]]]},"properties":{"name":"Small Square WV69 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-2.10175404400228,49.6022201872867]},"properties":{"name":"WV69"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.0490795575265,48.7473473374598],[-2.04737894941748,48.8372724480407],[-1.91115933073751,48.8360663669895],[-1.91310307516506,48.7461450443241],[-2.0490795575265,48.7473473374598]]]},"properties":{"name":"Small Square WV70 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.98017333123726,48.791732502436]},"properties":{"name":"WV70"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.04737877891833,48.8372814413784],[-2.04566972716024,48.9272050992897],[-1.90920574121458,48.9259952164404],[-1.91115913586209,48.8360753599477],[-2.04737877891833,48.8372814413784]]]},"properties":{"name":"Small Square WV71 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.97834643617162,48.8816640454743]},"properties":{"name":"WV71"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.04566955581396,48.9272140924822],[-2.04395200650067,49.017136298081],[-1.90724243890045,49.0159225998373],[-1.90920554537097,48.9260042092521],[-2.04566955581396,48.9272140924822]]]},"properties":{"name":"Small Square WV72 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.97651046432308,48.9715941293249]},"properties":{"name":"WV72"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.04395183430183,49.0171452911283],[-2.04222573304928,49.107066044783],[-1.90526936163978,49.1058485174559],[-1.90724224208246,49.0159315925024],[-2.04395183430183,49.0171452911283]]]},"properties":{"name":"Small Square WV73 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.97466535767483,49.0615227543058]},"properties":{"name":"WV73"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.04222555999243,49.1070750376851],[-2.0404908519333,49.1969943397753],[-1.90328644672501,49.1957729695821],[-1.90526916384117,49.1058575099743],[-2.04222555999243,49.1070750376851]]]},"properties":{"name":"Small Square WV74 Boundry Box","tessellate":true}}, {"type":"Feature","geometry":{"type":"Point","coordinates":[-1.97281105769514,49.1514499207462]},"properties":{"name":"WV74"}}, {"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.04049067801293,49.1970033325323],[-2.03874730779145,49.2869211834487],[-1.90129363089038,49.2856959565125],[-1.90328624793948,49.1957819619541],[-2.04049067801293,49.1970033325323]]]},"properties":{"name":"Small Square WV75 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.9709475053317,49.2413756289858]},"properties":{"name":"WV75"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.03874713300199,49.2869301760605],[-2.03699504476849,49.376846576205],[-1.89929085030569,49.3756174785538],[-1.90129343111157,49.285704948738],[-2.03874713300199,49.2869301760605]]]},"properties":{"name":"Small Square WV76 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.96907464100597,49.3312998793751]},"properties":{"name":"WV76"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.03699486910432,49.3768555686717],[-2.03523400650979,49.4667705184572],[-1.89727804057018,49.4655375360228],[-1.89929064952721,49.3756264706327],[-2.03699486910432,49.3768555686717]]]},"properties":{"name":"Small Square WV77 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.96719240460727,49.4212226722754]},"properties":{"name":"WV77"}}, -{"type":"Feature","geometry":{"type":"MultiLineString","coordinates":[[[-2.03523382996527,49.4667795107789],[-2.03346413615585,49.5566930106293],[-1.89525513670613,49.5554561292467],[-1.89727783878554,49.4655465279553],[-2.03523382996527,49.4667795107789]]]},"properties":{"name":"Small Square WV78 Boundry Box","tessellate":true}}, -{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.96530073548699,49.5111440080584]},"properties":{"name":"WV78"}} +{"type":"Feature","geometry":{"type":"Point","coordinates":[-1.9709475053317,49.2413756289858]},"properties":{"name":"WV75"}} ]} From 93bcc979ab9107ec1d5f08e3372df5f68a780c38 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 30 Apr 2024 13:53:02 +0100 Subject: [PATCH 26/37] updated package files --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc2f192a5..da0cd776d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "cypress": "^13.7.2" + "cypress": "^13.8.1" } }, "node_modules/@colors/colors": { @@ -533,9 +533,9 @@ } }, "node_modules/cypress": { - "version": "13.7.2", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.7.2.tgz", - "integrity": "sha512-FF5hFI5wlRIHY8urLZjJjj/YvfCBrRpglbZCLr/cYcL9MdDe0+5usa8kTIrDHthlEc9lwihbkb5dmwqBDNS2yw==", + "version": "13.8.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.8.1.tgz", + "integrity": "sha512-Uk6ovhRbTg6FmXjeZW/TkbRM07KPtvM5gah1BIMp4Y2s+i/NMxgaLw0+PbYTOdw1+egE0FP3mWRiGcRkjjmhzA==", "dev": true, "hasInstallScript": true, "dependencies": { diff --git a/package.json b/package.json index a3dfc75cd..97e411157 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,6 @@ "author": "", "license": "ISC", "devDependencies": { - "cypress": "^13.7.2" + "cypress": "^13.8.1" } } From 471c83a8b8acae6e2da47a6729af5ad34b003d7c Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 30 Apr 2024 14:48:47 +0100 Subject: [PATCH 27/37] Impliments a simple remember me feature for 14 days Starts to impliment #3087 this has a remember me for 14 days --- application/controllers/User.php | 28 +++++++++++++++++++ .../language/bulgarian/account_lang.php | 1 + .../chinese_simplified/account_lang.php | 1 + application/language/czech/account_lang.php | 2 +- application/language/dutch/account_lang.php | 1 + application/language/english/account_lang.php | 2 ++ application/language/finnish/account_lang.php | 1 + application/language/french/account_lang.php | 1 + application/language/german/account_lang.php | 1 + application/language/greek/account_lang.php | 1 + application/language/italian/account_lang.php | 1 + application/language/polish/account_lang.php | 1 + application/language/russian/account_lang.php | 1 + application/language/spanish/account_lang.php | 1 + application/language/swedish/account_lang.php | 1 + application/language/turkish/account_lang.php | 1 + application/views/user/login.php | 6 ++++ 17 files changed, 50 insertions(+), 1 deletion(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index ce1d59f52..7a37a833b 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -877,6 +877,8 @@ function delete() { function login() { // Check our version and run any migrations $this->load->library('Migration'); + $this->load->library('encrypt'); + $this->migration->current(); $this->load->model('user_model'); @@ -889,6 +891,16 @@ function login() { $data['user'] = $query->row(); + // Read the cookie remeber_me and log the user in + if($this->input->cookie('remember_me')) { + $encrypted_string = $this->input->cookie('remember_me'); + $decrypted_string = $this->encrypt->decode($encrypted_string); + $this->user_model->update_session($decrypted_string); + $this->user_model->set_last_login($decrypted_string); + // set a debug message + $this->session->set_flashdata('notice', 'User logged in'); + redirect('dashboard'); + } if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Login"; @@ -910,6 +922,19 @@ function login() { ); $this->input->set_cookie($cookie); + + // Create a remember me cookie + if($this->input->post('remember_me') == '1') { + $encrypted_string = $this->encrypt->encode($data['user']->user_id); + + $cookie= array( + 'name' => 'remember_me', + 'value' => $encrypted_string, + 'expire' => '1209600', + 'secure' => FALSE + ); + $this->input->set_cookie($cookie); + } redirect('dashboard'); } else { $this->session->set_flashdata('error', 'Incorrect username or password!'); @@ -923,6 +948,9 @@ function logout() { $user_name = $this->session->userdata('user_name'); + // Delete remember_me cookie + setcookie('remember_me', '', time() - 3600, '/'); + $this->user_model->clear_session(); $this->session->set_flashdata('notice', 'User '.$user_name.' logged out.'); diff --git a/application/language/bulgarian/account_lang.php b/application/language/bulgarian/account_lang.php index 339c8213f..99886560e 100644 --- a/application/language/bulgarian/account_lang.php +++ b/application/language/bulgarian/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Create User Account'; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/chinese_simplified/account_lang.php b/application/language/chinese_simplified/account_lang.php index ffcf33d31..8326e2d66 100644 --- a/application/language/chinese_simplified/account_lang.php +++ b/application/language/chinese_simplified/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = '创建账户'; $lang['account_edit_account'] = '编辑账户'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = '账户信息'; $lang['account_user'] = "用户"; diff --git a/application/language/czech/account_lang.php b/application/language/czech/account_lang.php index 2e51f1309..ab1f1dcd8 100644 --- a/application/language/czech/account_lang.php +++ b/application/language/czech/account_lang.php @@ -11,7 +11,7 @@ $lang['account_create_user_account'] = 'Vytvořit uživatelský účet'; $lang['account_edit_account'] = 'Upravit účet'; - +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = 'Informace o účtu'; $lang['account_user'] = "User"; $lang['account_word_edited'] = "edited"; diff --git a/application/language/dutch/account_lang.php b/application/language/dutch/account_lang.php index 7387aef38..22a7b1abb 100644 --- a/application/language/dutch/account_lang.php +++ b/application/language/dutch/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Create User Account'; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/english/account_lang.php b/application/language/english/account_lang.php index 045160f70..13fe9b86c 100644 --- a/application/language/english/account_lang.php +++ b/application/language/english/account_lang.php @@ -133,3 +133,5 @@ $lang['account_hamsat_hint'] = "See your profile at https://hams.at/users/settings."; $lang['account_hamsat_workable_only'] = "Show Workable Passes Only"; $lang['account_hamsat_workable_only_hint'] = "If enabled shows only workable passes based on the gridsquare set in your hams.at account. Requires private feed key to be set."; + +$lang['account_remember_me'] = 'Remember me'; \ No newline at end of file diff --git a/application/language/finnish/account_lang.php b/application/language/finnish/account_lang.php index 0a2e51e2b..4e8d589b7 100644 --- a/application/language/finnish/account_lang.php +++ b/application/language/finnish/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Luo käyttäjätili'; $lang['account_edit_account'] = 'Muokkaa käyttäjätiliä'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/french/account_lang.php b/application/language/french/account_lang.php index 1b41f7858..2aeaad959 100644 --- a/application/language/french/account_lang.php +++ b/application/language/french/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = "Créer un compte"; $lang['account_edit_account'] = "Editer un compte"; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Compte"; $lang['account_user'] = "Compte"; diff --git a/application/language/german/account_lang.php b/application/language/german/account_lang.php index 0499cb586..ba369f5d3 100644 --- a/application/language/german/account_lang.php +++ b/application/language/german/account_lang.php @@ -8,6 +8,7 @@ $lang['account_column3_text'] = 'Wähle Spalte 3'; $lang['account_column4_text'] = 'Wähle Spalte 4'; $lang['account_column5_text'] = 'Wähle Spalte 5 (nur für Logbuch)'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_create_user_account'] = 'Benutzerkonto anlegen'; $lang['account_edit_account'] = 'Benutzerkonto editieren'; diff --git a/application/language/greek/account_lang.php b/application/language/greek/account_lang.php index 1891aba4e..289f70cdd 100644 --- a/application/language/greek/account_lang.php +++ b/application/language/greek/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = "Create User Account"; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/italian/account_lang.php b/application/language/italian/account_lang.php index 9b0ad70db..d87f0e414 100644 --- a/application/language/italian/account_lang.php +++ b/application/language/italian/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Create User Account'; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/polish/account_lang.php b/application/language/polish/account_lang.php index 9a7ea5427..2c4f0d485 100644 --- a/application/language/polish/account_lang.php +++ b/application/language/polish/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Create User Account'; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/language/russian/account_lang.php b/application/language/russian/account_lang.php index 32b2c521b..dbf3b32d1 100644 --- a/application/language/russian/account_lang.php +++ b/application/language/russian/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = ' Создать аккаунт пользователя'; $lang['account_edit_account'] = 'Редактировать аккаунт'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = 'Информация об аккаунте'; $lang['account_user'] = "User"; diff --git a/application/language/spanish/account_lang.php b/application/language/spanish/account_lang.php index cedf07ea1..ae57d1af5 100644 --- a/application/language/spanish/account_lang.php +++ b/application/language/spanish/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Crear Cuenta de Usuario'; $lang['account_edit_account'] = 'Editar Cuenta'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = 'Información de la Cuenta'; $lang['account_user'] = "Usuario"; diff --git a/application/language/swedish/account_lang.php b/application/language/swedish/account_lang.php index a63fdbc17..d3d9d27cb 100644 --- a/application/language/swedish/account_lang.php +++ b/application/language/swedish/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Skapa användarkonto'; $lang['account_edit_account'] = 'Redigera användarkonto'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = 'Användarkontoinformation'; $lang['account_user'] = "User"; diff --git a/application/language/turkish/account_lang.php b/application/language/turkish/account_lang.php index 867fa9376..1a332cd45 100644 --- a/application/language/turkish/account_lang.php +++ b/application/language/turkish/account_lang.php @@ -11,6 +11,7 @@ $lang['account_create_user_account'] = 'Create User Account'; $lang['account_edit_account'] = 'Edit Account'; +$lang['account_remember_me'] = 'Remember me'; $lang['account_account_information'] = "Account"; $lang['account_user'] = "User"; diff --git a/application/views/user/login.php b/application/views/user/login.php index 32db00e1d..bdb90842c 100644 --- a/application/views/user/login.php +++ b/application/views/user/login.php @@ -51,6 +51,12 @@ placeholder=""> + +
+ +

From a29bf27ed1a2bba08a030f194decc9488308243f Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 30 Apr 2024 15:55:36 +0100 Subject: [PATCH 28/37] Increase COL_CREDIT_SUBMITTED to 255 --- application/config/migration.php | 2 +- ...80_qso_table_credit_submitted_increase.php | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 application/migrations/180_qso_table_credit_submitted_increase.php diff --git a/application/config/migration.php b/application/config/migration.php index 652244a91..cba5ee184 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ | */ -$config['migration_version'] = 179; +$config['migration_version'] = 180; /* |-------------------------------------------------------------------------- diff --git a/application/migrations/180_qso_table_credit_submitted_increase.php b/application/migrations/180_qso_table_credit_submitted_increase.php new file mode 100644 index 000000000..e5fcf4caf --- /dev/null +++ b/application/migrations/180_qso_table_credit_submitted_increase.php @@ -0,0 +1,27 @@ + array( + 'name' => 'COL_CREDIT_SUBMITTED', + 'type' => 'VARCHAR', + 'constraint' => '255', + ) + ); + $this->dbforge->modify_column($this->config->item('table_name'), $fields); + } + + public function down() + { + echo "Not possible, sorry."; + } +} \ No newline at end of file From 2c0e9b8c5da9eb2ca316aa1861a0ee624dd1a76b Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Tue, 30 Apr 2024 17:26:26 +0100 Subject: [PATCH 29/37] set a debug message --- application/controllers/User.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index 7a37a833b..ea219f8b3 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -897,8 +897,9 @@ function login() { $decrypted_string = $this->encrypt->decode($encrypted_string); $this->user_model->update_session($decrypted_string); $this->user_model->set_last_login($decrypted_string); - // set a debug message - $this->session->set_flashdata('notice', 'User logged in'); + + log_message('debug', 'Remember Me Login Successful'); + redirect('dashboard'); } From 6120574bd3d4751b56913444c1df4ef08264b903 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 1 May 2024 10:47:00 +0100 Subject: [PATCH 30/37] Remember Me: pickup the cookie prefix if one is there --- application/controllers/User.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index ea219f8b3..cbc605a2e 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -892,8 +892,8 @@ function login() { $data['user'] = $query->row(); // Read the cookie remeber_me and log the user in - if($this->input->cookie('remember_me')) { - $encrypted_string = $this->input->cookie('remember_me'); + if($this->input->cookie(config_item('cookie_prefix').'remember_me')) { + $encrypted_string = $this->input->cookie(config_item('cookie_prefix').'remember_me'); $decrypted_string = $this->encrypt->decode($encrypted_string); $this->user_model->update_session($decrypted_string); $this->user_model->set_last_login($decrypted_string); From 6aadfbf74af70db01f4b51db3cd055e199935ef0 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 1 May 2024 10:53:51 +0100 Subject: [PATCH 31/37] Update User.php --- application/controllers/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index cbc605a2e..1512eaeeb 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -898,7 +898,7 @@ function login() { $this->user_model->update_session($decrypted_string); $this->user_model->set_last_login($decrypted_string); - log_message('debug', 'Remember Me Login Successful'); + log_message('debug', '[User ID: '.$decrypted_string.'] Remember Me Login Successful'); redirect('dashboard'); } From f60e909459b34c5430ba1a315436499e069bfa7a Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Wed, 1 May 2024 21:57:25 +0100 Subject: [PATCH 32/37] improved encryption --- application/controllers/User.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index 1512eaeeb..75bb78de5 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -877,7 +877,7 @@ function delete() { function login() { // Check our version and run any migrations $this->load->library('Migration'); - $this->load->library('encrypt'); + $this->load->library('encryption'); $this->migration->current(); @@ -894,7 +894,7 @@ function login() { // Read the cookie remeber_me and log the user in if($this->input->cookie(config_item('cookie_prefix').'remember_me')) { $encrypted_string = $this->input->cookie(config_item('cookie_prefix').'remember_me'); - $decrypted_string = $this->encrypt->decode($encrypted_string); + $decrypted_string = $this->encryption->decrypt($encrypted_string); $this->user_model->update_session($decrypted_string); $this->user_model->set_last_login($decrypted_string); @@ -926,7 +926,7 @@ function login() { // Create a remember me cookie if($this->input->post('remember_me') == '1') { - $encrypted_string = $this->encrypt->encode($data['user']->user_id); + $encrypted_string = $this->encryption->encrypt($data['user']->user_id); $cookie= array( 'name' => 'remember_me', From 9037bf8dadb5cf33bf51f71f7ba3c3d013aebdc4 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Thu, 2 May 2024 12:12:40 +0100 Subject: [PATCH 33/37] Catch any errors --- application/controllers/User.php | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index 75bb78de5..df6dceaaa 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -893,14 +893,21 @@ function login() { // Read the cookie remeber_me and log the user in if($this->input->cookie(config_item('cookie_prefix').'remember_me')) { - $encrypted_string = $this->input->cookie(config_item('cookie_prefix').'remember_me'); - $decrypted_string = $this->encryption->decrypt($encrypted_string); - $this->user_model->update_session($decrypted_string); - $this->user_model->set_last_login($decrypted_string); - - log_message('debug', '[User ID: '.$decrypted_string.'] Remember Me Login Successful'); - - redirect('dashboard'); + try { + $encrypted_string = $this->input->cookie(config_item('cookie_prefix').'remember_me'); + $decrypted_string = $this->encryption->decrypt($encrypted_string); + $this->user_model->update_session($decrypted_string); + $this->user_model->set_last_login($decrypted_string); + + log_message('debug', '[User ID: '.$decrypted_string.'] Remember Me Login Successful'); + + redirect('dashboard'); + } catch (Exception $e) { + // Something went wrong with the cookie + log_message('error', 'Remember Me Login Failed'); + $this->session->set_flashdata('error', 'Remember Me Login Failed'); + redirect('user/login'); + } } if ($this->form_validation->run() == FALSE) { From c33ce3fdbb0ec19d1098cc8b94677faeb19c5627 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Thu, 2 May 2024 13:48:45 +0100 Subject: [PATCH 34/37] Cleaned up code a bit --- application/controllers/User.php | 557 ++++++++++++++++--------------- 1 file changed, 291 insertions(+), 266 deletions(-) diff --git a/application/controllers/User.php b/application/controllers/User.php index df6dceaaa..9ec6ffe9a 100644 --- a/application/controllers/User.php +++ b/application/controllers/User.php @@ -1,36 +1,53 @@ -lang->load(array( - 'account', - 'lotw', - 'eqsl', - 'admin', - )); + $this->lang->load(array( + 'account', + 'lotw', + 'eqsl', + 'admin', + )); } + /** + * Index method for the User controller. + * This method loads the user model, authorizes the user, and displays the user accounts. + */ public function index() { $this->load->model('user_model'); - if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + + // Check if the user is authorized + if (!$this->user_model->authorize(99)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } + // Get the user accounts $data['results'] = $this->user_model->users(); + // Set the page title $data['page_title'] = $this->lang->line('admin_user_accounts'); + // Load the views $this->load->view('interface_assets/header', $data); $this->load->view('user/main'); $this->load->view('interface_assets/footer'); } - function add() { + function add() + { $this->load->model('user_model'); - if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (!$this->user_model->authorize(99)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $data['existing_languages'] = $this->find(); @@ -59,67 +76,67 @@ function add() { $data['timezones'] = $this->user_model->timezones(); $data['language'] = 'english'; - // Set defaults + // Set defaults + $data['dashboard_upcoming_dx_card'] = false; + $data['dashboard_qslcard_card'] = false; + $data['dashboard_eqslcard_card'] = false; + $data['dashboard_lotw_card'] = false; + $data['dashboard_vuccgrids_card'] = false; + + $dashboard_options = $this->user_options_model->get_options('dashboard')->result(); + + foreach ($dashboard_options as $item) { + $option_name = $item->option_name; + $option_key = $item->option_key; + $option_value = $item->option_value; + + if ($option_name == 'dashboard_upcoming_dx_card' && $option_key == 'enabled') { + if ($item->option_value == 'true') { + $data['dashboard_upcoming_dx_card'] = true; + } else { $data['dashboard_upcoming_dx_card'] = false; + } + } + + if ($option_name == 'dashboard_qslcards_card' && $option_key == 'enabled') { + if ($item->option_value == 'true') { + $data['dashboard_qslcard_card'] = true; + } else { $data['dashboard_qslcard_card'] = false; + } + } + + if ($option_name == 'dashboard_eqslcards_card' && $option_key == 'enabled') { + if ($item->option_value == 'true') { + $data['dashboard_eqslcard_card'] = true; + } else { $data['dashboard_eqslcard_card'] = false; + } + } + + if ($option_name == 'dashboard_lotw_card' && $option_key == 'enabled') { + if ($item->option_value == 'true') { + $data['dashboard_lotw_card'] = true; + } else { $data['dashboard_lotw_card'] = false; + } + } + + if ($option_name == 'dashboard_vuccgrids_card' && $option_key == 'enabled') { + if ($item->option_value == 'true') { + $data['dashboard_vuccgrids_card'] = true; + } else { $data['dashboard_vuccgrids_card'] = false; - - $dashboard_options = $this->user_options_model->get_options('dashboard')->result(); - - foreach ($dashboard_options as $item) { - $option_name = $item->option_name; - $option_key = $item->option_key; - $option_value = $item->option_value; - - if ($option_name == 'dashboard_upcoming_dx_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { - $data['dashboard_upcoming_dx_card'] = true; - } else { - $data['dashboard_upcoming_dx_card'] = false; - } - } - - if ($option_name == 'dashboard_qslcards_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { - $data['dashboard_qslcard_card'] = true; - } else { - $data['dashboard_qslcard_card'] = false; - } - } - - if ($option_name == 'dashboard_eqslcards_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { - $data['dashboard_eqslcard_card'] = true; - } else { - $data['dashboard_eqslcard_card'] = false; - } - } - - if ($option_name == 'dashboard_lotw_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { - $data['dashboard_lotw_card'] = true; - } else { - $data['dashboard_lotw_card'] = false; - } - } - - if ($option_name == 'dashboard_vuccgrids_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { - $data['dashboard_vuccgrids_card'] = true; - } else { - $data['dashboard_vuccgrids_card'] = false; - } - } - } + } + } + } if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Add User"; - $data['measurement_base'] = $this->config->item('measurement_base'); + $data['measurement_base'] = $this->config->item('measurement_base'); $this->load->view('interface_assets/header', $data); - if($this->input->post('user_name')) { + if ($this->input->post('user_name')) { $data['user_name'] = $this->input->post('user_name'); $data['user_email'] = $this->input->post('user_email'); $data['user_password'] = $this->input->post('user_password'); @@ -146,7 +163,7 @@ function add() { $data['user_amsat_status_upload'] = $this->input->post('user_amsat_status_upload'); $data['user_mastodon_url'] = $this->input->post('user_mastodon_url'); $data['user_default_band'] = $this->input->post('user_default_band'); - $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '').($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '').($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '').($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); + $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '') . ($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '') . ($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '') . ($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); $data['user_qso_end_times'] = $this->input->post('user_qso_end_times'); $data['user_quicklog'] = $this->input->post('user_quicklog'); $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter'); @@ -159,7 +176,8 @@ function add() { } $this->load->view('interface_assets/footer'); } else { - switch($this->user_model->add($this->input->post('user_name'), + switch ($this->user_model->add( + $this->input->post('user_name'), $this->input->post('user_password'), $this->input->post('user_email'), $this->input->post('user_type'), @@ -186,27 +204,27 @@ function add() { $this->input->post('user_amsat_status_upload'), $this->input->post('user_mastodon_url'), $this->input->post('user_default_band'), - ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '').($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '').($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '').($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''), + ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '') . ($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '') . ($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '') . ($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''), $this->input->post('user_qso_end_times'), $this->input->post('user_quicklog'), $this->input->post('user_quicklog_enter'), $this->input->post('language'), $this->input->post('user_hamsat_key'), - $this->input->post('user_hamsat_workable_only') - )) { - // Check for errors + $this->input->post('user_hamsat_workable_only') + )) { + // Check for errors case EUSERNAMEEXISTS: - $data['username_error'] = 'Username '.$this->input->post('user_name').' already in use!'; + $data['username_error'] = 'Username ' . $this->input->post('user_name') . ' already in use!'; break; case EEMAILEXISTS: - $data['email_error'] = 'E-mail address '.$this->input->post('user_email').' already in use!'; + $data['email_error'] = 'E-mail address ' . $this->input->post('user_email') . ' already in use!'; break; case EPASSWORDINVALID: $data['password_error'] = 'Invalid password!'; break; - // All okay, return to user screen + // All okay, return to user screen case OK: - $this->session->set_flashdata('notice', 'User '.$this->input->post('user_name').' added'); + $this->session->set_flashdata('notice', 'User ' . $this->input->post('user_name') . ' added'); redirect('user'); return; } @@ -238,7 +256,7 @@ function add() { $data['user_amsat_status_upload'] = $this->input->post('user_amsat_status_upload'); $data['user_mastodon_url'] = $this->input->post('user_mastodon_url'); $data['user_default_band'] = $this->input->post('user_default_band'); - $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '').($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '').($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '').($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); + $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '') . ($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '') . ($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '') . ($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); $data['user_qso_end_times'] = $this->input->post('user_qso_end_times'); $data['user_quicklog'] = $this->input->post('user_quicklog'); $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter'); @@ -248,25 +266,30 @@ function add() { } } - function find() { + function find() + { $existing_langs = array(); - $lang_path = APPPATH.'language'; + $lang_path = APPPATH . 'language'; $results = scandir($lang_path); foreach ($results as $result) { if ($result === '.' or $result === '..') continue; - if (is_dir(APPPATH.'language' . '/' . $result)) { + if (is_dir(APPPATH . 'language' . '/' . $result)) { $dirs[] = $result; } } return $dirs; } - function edit() { + function edit() + { $this->load->model('user_model'); - if ( ($this->session->userdata('user_id') == '') || ((!$this->user_model->authorize(99)) && ($this->session->userdata('user_id') != $this->uri->segment(3))) ) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (($this->session->userdata('user_id') == '') || ((!$this->user_model->authorize(99)) && ($this->session->userdata('user_id') != $this->uri->segment(3)))) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $query = $this->user_model->get_by_id($this->uri->segment(3)); $data['existing_languages'] = $this->find(); @@ -276,8 +299,7 @@ function edit() { $this->form_validation->set_rules('user_name', 'Username', 'required|xss_clean'); $this->form_validation->set_rules('user_email', 'E-mail', 'required|xss_clean'); - if($this->session->userdata('user_type') == 99) - { + if ($this->session->userdata('user_type') == 99) { $this->form_validation->set_rules('user_type', 'Type', 'required|xss_clean'); } $this->form_validation->set_rules('user_firstname', 'First name', 'required|xss_clean'); @@ -286,7 +308,7 @@ function edit() { $this->form_validation->set_rules('user_locator', 'Locator', 'callback_check_locator'); $this->form_validation->set_rules('user_timezone', 'Timezone', 'required'); - $data['user_form_action'] = site_url('user/edit')."/".$this->uri->segment(3);; + $data['user_form_action'] = site_url('user/edit') . "/" . $this->uri->segment(3);; $data['bands'] = $this->bands->get_user_bands(); // Get themes list @@ -295,256 +317,255 @@ function edit() { // Get timezones $data['timezones'] = $this->user_model->timezones(); - if ($this->form_validation->run() == FALSE) - { + if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Edit User"; $q = $query->row(); $data['id'] = $q->user_id; - if($this->input->post('user_name', true)) { + if ($this->input->post('user_name', true)) { $data['user_name'] = $this->input->post('user_name', true); } else { $data['user_name'] = $q->user_name; } - if($this->input->post('user_email', true)) { + if ($this->input->post('user_email', true)) { $data['user_email'] = $this->input->post('user_email', true); } else { $data['user_email'] = $q->user_email; } - if($this->input->post('user_password', true)) { - $data['user_password'] = $this->input->post('user_password',true); + if ($this->input->post('user_password', true)) { + $data['user_password'] = $this->input->post('user_password', true); } else { $data['user_password'] = $q->user_password; } - if($this->input->post('user_type', true)) { - $data['user_type'] = $this->input->post('user_type',true); + if ($this->input->post('user_type', true)) { + $data['user_type'] = $this->input->post('user_type', true); } else { $data['user_type'] = $q->user_type; } - if($this->input->post('user_callsign', true)) { + if ($this->input->post('user_callsign', true)) { $data['user_callsign'] = $this->input->post('user_callsign', true); } else { $data['user_callsign'] = $q->user_callsign; } - if($this->input->post('user_locator', true)) { + if ($this->input->post('user_locator', true)) { $data['user_locator'] = $this->input->post('user_locator', true); } else { $data['user_locator'] = $q->user_locator; } - if($this->input->post('user_firstname', true)) { + if ($this->input->post('user_firstname', true)) { $data['user_firstname'] = $this->input->post('user_firstname', true); } else { $data['user_firstname'] = $q->user_firstname; } - if($this->input->post('user_lastname', true)) { + if ($this->input->post('user_lastname', true)) { $data['user_lastname'] = $this->input->post('user_lastname', true); } else { $data['user_lastname'] = $q->user_lastname; } - if($this->input->post('user_callsign', true)) { + if ($this->input->post('user_callsign', true)) { $data['user_callsign'] = $this->input->post('user_callsign', true); } else { $data['user_callsign'] = $q->user_callsign; } - if($this->input->post('user_locator', true)) { + if ($this->input->post('user_locator', true)) { $data['user_locator'] = $this->input->post('user_locator', true); } else { $data['user_locator'] = $q->user_locator; } - if($this->input->post('user_timezone')) { + if ($this->input->post('user_timezone')) { $data['user_timezone'] = $this->input->post('user_timezone', true); } else { $data['user_timezone'] = $q->user_timezone; } - if($this->input->post('user_lotw_name')) { + if ($this->input->post('user_lotw_name')) { $data['user_lotw_name'] = $this->input->post('user_lotw_name', true); } else { $data['user_lotw_name'] = $q->user_lotw_name; } - if($this->input->post('user_clublog_name')) { + if ($this->input->post('user_clublog_name')) { $data['user_clublog_name'] = $this->input->post('user_clublog_name', true); } else { $data['user_clublog_name'] = $q->user_clublog_name; } - if($this->input->post('user_clublog_password')) { + if ($this->input->post('user_clublog_password')) { $data['user_clublog_password'] = $this->input->post('user_clublog_password', true); } else { $data['user_clublog_password'] = $q->user_clublog_password; } - if($this->input->post('user_lotw_password')) { + if ($this->input->post('user_lotw_password')) { $data['user_lotw_password'] = $this->input->post('user_lotw_password', true); } else { $data['user_lotw_password'] = $q->user_lotw_password; } - if($this->input->post('user_eqsl_name')) { + if ($this->input->post('user_eqsl_name')) { $data['user_eqsl_name'] = $this->input->post('user_eqsl_name', true); } else { $data['user_eqsl_name'] = $q->user_eqsl_name; } - if($this->input->post('user_eqsl_password')) { + if ($this->input->post('user_eqsl_password')) { $data['user_eqsl_password'] = $this->input->post('user_eqsl_password', true); } else { $data['user_eqsl_password'] = $q->user_eqsl_password; } - if($this->input->post('user_measurement_base')) { + if ($this->input->post('user_measurement_base')) { $data['user_measurement_base'] = $this->input->post('user_measurement_base', true); } else { $data['user_measurement_base'] = $q->user_measurement_base; } - if($this->input->post('user_date_format')) { + if ($this->input->post('user_date_format')) { $data['user_date_format'] = $this->input->post('user_date_format', true); } else { $data['user_date_format'] = $q->user_date_format; } - if($this->input->post('language')) { + if ($this->input->post('language')) { $data['language'] = $this->input->post('language', true); } else { $data['language'] = $q->language; } - - if($this->input->post('user_stylesheet')) { + + if ($this->input->post('user_stylesheet')) { $data['user_stylesheet'] = $this->input->post('user_stylesheet', true); } else { $data['user_stylesheet'] = $q->user_stylesheet; } - if($this->input->post('user_qth_lookup')) { + if ($this->input->post('user_qth_lookup')) { $data['user_qth_lookup'] = $this->input->post('user_qth_lookup', true); } else { $data['user_qth_lookup'] = $q->user_qth_lookup; } - if($this->input->post('user_sota_lookup')) { + if ($this->input->post('user_sota_lookup')) { $data['user_sota_lookup'] = $this->input->post('user_sota_lookup', true); } else { $data['user_sota_lookup'] = $q->user_sota_lookup; } - if($this->input->post('user_wwff_lookup')) { + if ($this->input->post('user_wwff_lookup')) { $data['user_wwff_lookup'] = $this->input->post('user_wwff_lookup', true); } else { $data['user_wwff_lookup'] = $q->user_wwff_lookup; } - if($this->input->post('user_pota_lookup')) { + if ($this->input->post('user_pota_lookup')) { $data['user_pota_lookup'] = $this->input->post('user_pota_lookup', true); } else { $data['user_pota_lookup'] = $q->user_pota_lookup; } - if($this->input->post('user_show_notes')) { + if ($this->input->post('user_show_notes')) { $data['user_show_notes'] = $this->input->post('user_show_notes', true); } else { $data['user_show_notes'] = $q->user_show_notes; } - if($this->input->post('user_qso_end_times')) { + if ($this->input->post('user_qso_end_times')) { $data['user_qso_end_times'] = $this->input->post('user_qso_end_times', true); } else { $data['user_qso_end_times'] = $q->user_qso_end_times; } - if($this->input->post('user_quicklog')) { + if ($this->input->post('user_quicklog')) { $data['user_quicklog'] = $this->input->post('user_quicklog', true); } else { $data['user_quicklog'] = $q->user_quicklog; } - if($this->input->post('user_quicklog_enter')) { + if ($this->input->post('user_quicklog_enter')) { $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter', true); } else { $data['user_quicklog_enter'] = $q->user_quicklog_enter; } - if($this->input->post('user_show_profile_image')) { + if ($this->input->post('user_show_profile_image')) { $data['user_show_profile_image'] = $this->input->post('user_show_profile_image', false); } else { $data['user_show_profile_image'] = $q->user_show_profile_image; } - if($this->input->post('user_previous_qsl_type')) { + if ($this->input->post('user_previous_qsl_type')) { $data['user_previous_qsl_type'] = $this->input->post('user_previous_qsl_type', false); } else { $data['user_previous_qsl_type'] = $q->user_previous_qsl_type; } - if($this->input->post('user_amsat_status_upload')) { + if ($this->input->post('user_amsat_status_upload')) { $data['user_amsat_status_upload'] = $this->input->post('user_amsat_status_upload', false); } else { $data['user_amsat_status_upload'] = $q->user_amsat_status_upload; } - if($this->input->post('user_mastodon_url')) { + if ($this->input->post('user_mastodon_url')) { $data['user_mastodon_url'] = $this->input->post('user_mastodon_url', false); } else { $data['user_mastodon_url'] = $q->user_mastodon_url; } - if($this->input->post('user_default_band')) { + if ($this->input->post('user_default_band')) { $data['user_default_band'] = $this->input->post('user_default_band', false); } else { $data['user_default_band'] = $q->user_default_band; } - if($this->input->post('user_default_confirmation')) { - $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '').($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '').($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '').($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); + if ($this->input->post('user_default_confirmation')) { + $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '') . ($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '') . ($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '') . ($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); } else { $data['user_default_confirmation'] = $q->user_default_confirmation; } - if($this->input->post('user_column1')) { + if ($this->input->post('user_column1')) { $data['user_column1'] = $this->input->post('user_column1', true); } else { $data['user_column1'] = $q->user_column1; } - if($this->input->post('user_column2')) { + if ($this->input->post('user_column2')) { $data['user_column2'] = $this->input->post('user_column2', true); } else { $data['user_column2'] = $q->user_column2; } - if($this->input->post('user_column3')) { + if ($this->input->post('user_column3')) { $data['user_column3'] = $this->input->post('user_column3', true); } else { $data['user_column3'] = $q->user_column3; } - if($this->input->post('user_column4')) { + if ($this->input->post('user_column4')) { $data['user_column4'] = $this->input->post('user_column4', true); } else { $data['user_column4'] = $q->user_column4; } - if($this->input->post('user_column5')) { + if ($this->input->post('user_column5')) { $data['user_column5'] = $this->input->post('user_column5', true); } else { $data['user_column5'] = $q->user_column5; } - if($this->input->post('user_winkey')) { + if ($this->input->post('user_winkey')) { $data['user_winkey'] = $this->input->post('user_winkey', true); } else { $data['user_winkey'] = $q->winkey; @@ -553,21 +574,21 @@ function edit() { $this->load->model('user_options_model'); $hamsat_user_object = $this->user_options_model->get_options('hamsat')->result(); - if($this->input->post('user_hamsat_key', true)) { + if ($this->input->post('user_hamsat_key', true)) { $data['user_hamsat_key'] = $this->input->post('user_hamsat_key', true); } else { // get $q->hamsat_key if its set if not null - if(isset($hamsat_user_object[0]->option_value)) { + if (isset($hamsat_user_object[0]->option_value)) { $data['user_hamsat_key'] = $hamsat_user_object[0]->option_value; } else { $data['user_hamsat_key'] = ""; } } - if($this->input->post('user_hamsat_workable_only')) { + if ($this->input->post('user_hamsat_workable_only')) { $data['user_hamsat_workable_only'] = $this->input->post('user_hamsat_workable_only', false); } else { - if(isset($hamsat_user_object[1]->option_value)) { + if (isset($hamsat_user_object[1]->option_value)) { $data['user_hamsat_workable_only'] = $hamsat_user_object[1]->option_value; } else { $data['user_hamsat_workable_only'] = ""; @@ -589,9 +610,9 @@ function edit() { $option_name = $item->option_name; $option_key = $item->option_key; $option_value = $item->option_value; - + if ($option_name == 'dashboard_upcoming_dx_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { + if ($item->option_value == 'true') { $data['dashboard_upcoming_dx_card'] = true; } else { $data['dashboard_upcoming_dx_card'] = false; @@ -599,7 +620,7 @@ function edit() { } if ($option_name == 'dashboard_qslcards_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { + if ($item->option_value == 'true') { $data['dashboard_qslcard_card'] = true; } else { $data['dashboard_qslcard_card'] = false; @@ -607,7 +628,7 @@ function edit() { } if ($option_name == 'dashboard_eqslcards_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { + if ($item->option_value == 'true') { $data['dashboard_eqslcard_card'] = true; } else { $data['dashboard_eqslcard_card'] = false; @@ -615,7 +636,7 @@ function edit() { } if ($option_name == 'dashboard_lotw_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { + if ($item->option_value == 'true') { $data['dashboard_lotw_card'] = true; } else { $data['dashboard_lotw_card'] = false; @@ -623,7 +644,7 @@ function edit() { } if ($option_name == 'dashboard_vuccgrids_card' && $option_key == 'enabled') { - if($item->option_value == 'true') { + if ($item->option_value == 'true') { $data['dashboard_vuccgrids_card'] = true; } else { $data['dashboard_vuccgrids_card'] = false; @@ -634,21 +655,21 @@ function edit() { // [MAP Custom] GET user options // $this->load->model('user_options_model'); $options_object = $this->user_options_model->get_options('map_custom')->result(); - if (count($options_object)>0) { + if (count($options_object) > 0) { foreach ($options_object as $row) { - if ($row->option_name=='icon') { - $option_value = json_decode($row->option_value,true); + if ($row->option_name == 'icon') { + $option_value = json_decode($row->option_value, true); foreach ($option_value as $ktype => $vtype) { - if($this->input->post('user_map_'.$row->option_key.'_icon')) { - $data['user_map_'.$row->option_key.'_'.$ktype] = $this->input->post('user_map_'.$row->option_key.'_'.$ktype, true); + if ($this->input->post('user_map_' . $row->option_key . '_icon')) { + $data['user_map_' . $row->option_key . '_' . $ktype] = $this->input->post('user_map_' . $row->option_key . '_' . $ktype, true); } else { - $data['user_map_'.$row->option_key.'_'.$ktype] = $vtype; - } + $data['user_map_' . $row->option_key . '_' . $ktype] = $vtype; + } } } else { - $data['user_map_'.$row->option_name.'_'.$row->option_key] = $row->option_value; + $data['user_map_' . $row->option_name . '_' . $row->option_key] = $row->option_value; } - } + } } else { $data['user_map_qso_icon'] = "fas fa-dot-circle"; $data['user_map_qso_color'] = "#FF0000"; @@ -659,40 +680,41 @@ function edit() { $data['user_map_gridsquare_show'] = "0"; } $data['map_icon_select'] = array( - 'station'=>array('0', 'fas fa-home', 'fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle' ), - 'qso'=>array('fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle' ), - 'qsoconfirm'=>array('0', 'fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle', 'fas fa-check-circle' )); - + 'station' => array('0', 'fas fa-home', 'fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle'), + 'qso' => array('fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle'), + 'qsoconfirm' => array('0', 'fas fa-broadcast-tower', 'fas fa-user', 'fas fa-dot-circle', 'fas fa-check-circle') + ); + $this->load->view('interface_assets/header', $data); $this->load->view('user/edit', $data); $this->load->view('interface_assets/footer'); } else { unset($data); - switch($this->user_model->edit($this->input->post())) { - // Check for errors + switch ($this->user_model->edit($this->input->post())) { + // Check for errors case EUSERNAMEEXISTS: - $data['username_error'] = 'Username '.$this->input->post('user_name', true).' already in use!'; + $data['username_error'] = 'Username ' . $this->input->post('user_name', true) . ' already in use!'; break; case EEMAILEXISTS: - $data['email_error'] = 'E-mail address '.$this->input->post('user_email', true).' already in use!'; + $data['email_error'] = 'E-mail address ' . $this->input->post('user_email', true) . ' already in use!'; break; case EPASSWORDINVALID: $data['password_error'] = 'Invalid password!'; break; - // All okay, return to user screen + // All okay, return to user screen case OK: if ($this->session->userdata('user_id') == $this->uri->segment(3)) { // Editing own User? Set cookie! - $cookie= array( + $cookie = array( 'name' => 'language', 'value' => $this->input->post('language', true), - 'expire' => time()+1000, + 'expire' => time() + 1000, 'secure' => FALSE ); $this->input->set_cookie($cookie); } - if($this->session->userdata('user_id') == $this->input->post('id', true)) { + if ($this->session->userdata('user_id') == $this->input->post('id', true)) { if (isset($_POST['user_dashboard_enable_dxpedition_card'])) { $this->user_options_model->set_option('dashboard', 'dashboard_upcoming_dx_card', array('enabled' => 'true')); } else { @@ -722,29 +744,29 @@ function edit() { } else { $this->user_options_model->set_option('dashboard', 'dashboard_vuccgrids_card', array('enabled' => 'false')); } - + // [MAP Custom] ADD to user options // - $array_icon = array('station','qso','qsoconfirm'); + $array_icon = array('station', 'qso', 'qsoconfirm'); foreach ($array_icon as $icon) { - $data_options['user_map_'.$icon.'_icon'] = xss_clean($this->input->post('user_map_'.$icon.'_icon', true)); - $data_options['user_map_'.$icon.'_color'] = xss_clean($this->input->post('user_map_'.$icon.'_color', true)); + $data_options['user_map_' . $icon . '_icon'] = xss_clean($this->input->post('user_map_' . $icon . '_icon', true)); + $data_options['user_map_' . $icon . '_color'] = xss_clean($this->input->post('user_map_' . $icon . '_color', true)); } $this->load->model('user_options_model'); if (!empty($data_options['user_map_qso_icon'])) { - foreach ($array_icon as $icon) { - $json = json_encode(array('icon'=>$data_options['user_map_'.$icon.'_icon'], 'color'=>$data_options['user_map_'.$icon.'_color'])); - $this->user_options_model->set_option('map_custom','icon',array($icon=>$json)); + foreach ($array_icon as $icon) { + $json = json_encode(array('icon' => $data_options['user_map_' . $icon . '_icon'], 'color' => $data_options['user_map_' . $icon . '_color'])); + $this->user_options_model->set_option('map_custom', 'icon', array($icon => $json)); } - $this->user_options_model->set_option('map_custom','gridsquare',array('show'=>xss_clean($this->input->post('user_map_gridsquare_show', true)))); + $this->user_options_model->set_option('map_custom', 'gridsquare', array('show' => xss_clean($this->input->post('user_map_gridsquare_show', true)))); } else { - $this->user_options_model->del_option('map_custom','icon'); - $this->user_options_model->del_option('map_custom','gridsquare'); + $this->user_options_model->del_option('map_custom', 'icon'); + $this->user_options_model->del_option('map_custom', 'gridsquare'); } - $this->session->set_flashdata('success', lang('account_user').' '.$this->input->post('user_name', true).' '.lang('account_word_edited')); - redirect('user/edit/'.$this->uri->segment(3)); + $this->session->set_flashdata('success', lang('account_user') . ' ' . $this->input->post('user_name', true) . ' ' . lang('account_word_edited')); + redirect('user/edit/' . $this->uri->segment(3)); } else { - $this->session->set_flashdata('success', lang('account_user').' '.$this->input->post('user_name', true).' '.lang('account_word_edited')); + $this->session->set_flashdata('success', lang('account_user') . ' ' . $this->input->post('user_name', true) . ' ' . lang('account_word_edited')); redirect('user'); } return; @@ -777,7 +799,7 @@ function edit() { $data['user_amsat_status_upload'] = $this->input->post('user_amsat_status_upload'); $data['user_mastodon_url'] = $this->input->post('user_mastodon_url'); $data['user_default_band'] = $this->input->post('user_default_band'); - $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '').($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '').($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '').($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); + $data['user_default_confirmation'] = ($this->input->post('user_default_confirmation_qsl') !== null ? 'Q' : '') . ($this->input->post('user_default_confirmation_lotw') !== null ? 'L' : '') . ($this->input->post('user_default_confirmation_eqsl') !== null ? 'E' : '') . ($this->input->post('user_default_confirmation_qrz') !== null ? 'Z' : ''); $data['user_qso_end_times'] = $this->input->post('user_qso_end_times'); $data['user_quicklog'] = $this->input->post('user_quicklog'); $data['user_quicklog_enter'] = $this->input->post('user_quicklog_enter'); @@ -793,19 +815,23 @@ function edit() { } } - function profile() { + function profile() + { $this->load->model('user_model'); - if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (!$this->user_model->authorize(2)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $query = $this->user_model->get_by_id($this->session->userdata('user_id')); - $q = $query->row(); - $data['page_title'] = "Profile"; - $data['user_name'] = $q->user_name; - $data['user_type'] = $q->user_type; - $data['user_email'] = $q->user_email; - $data['user_firstname'] = $q->user_firstname; - $data['user_lastname'] = $q->user_lastname; - $data['user_callsign'] = $q->user_callsign; - $data['user_locator'] = $q->user_locator; + $q = $query->row(); + $data['page_title'] = "Profile"; + $data['user_name'] = $q->user_name; + $data['user_type'] = $q->user_type; + $data['user_email'] = $q->user_email; + $data['user_firstname'] = $q->user_firstname; + $data['user_lastname'] = $q->user_lastname; + $data['user_callsign'] = $q->user_callsign; + $data['user_locator'] = $q->user_locator; $this->load->view('interface_assets/header', $data); $this->load->view('user/profile'); @@ -827,9 +853,13 @@ function profile() { * * @param int $id The ID of the user to delete. */ - function delete_new($id) { + function delete_new($id) + { $this->load->model('user_model'); - if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (!$this->user_model->authorize(99)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $query = $this->user_model->get_by_id($this->uri->segment(3)); // call $this->user_model->delete and if no errors return true @@ -840,12 +870,15 @@ function delete_new($id) { // request responds with a 500 status code and empty content $this->output->set_status_header(500); } - } - function delete() { + function delete() + { $this->load->model('user_model'); - if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (!$this->user_model->authorize(99)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $query = $this->user_model->get_by_id($this->uri->segment(3)); $this->load->library('form_validation'); @@ -854,17 +887,13 @@ function delete() { $data = $query->row(); - if ($this->form_validation->run() == FALSE) - { + if ($this->form_validation->run() == FALSE) { $this->load->view('interface_assets/header', $data); $this->load->view('user/delete'); $this->load->view('interface_assets/footer'); - } - else - { - if($this->user_model->delete($data->user_id)) - { + } else { + if ($this->user_model->delete($data->user_id)) { $this->session->set_flashdata('notice', 'User deleted'); redirect('user'); } else { @@ -874,7 +903,8 @@ function delete() { } } - function login() { + function login() + { // Check our version and run any migrations $this->load->library('Migration'); $this->load->library('encryption'); @@ -892,15 +922,15 @@ function login() { $data['user'] = $query->row(); // Read the cookie remeber_me and log the user in - if($this->input->cookie(config_item('cookie_prefix').'remember_me')) { + if ($this->input->cookie(config_item('cookie_prefix') . 'remember_me')) { try { - $encrypted_string = $this->input->cookie(config_item('cookie_prefix').'remember_me'); + $encrypted_string = $this->input->cookie(config_item('cookie_prefix') . 'remember_me'); $decrypted_string = $this->encryption->decrypt($encrypted_string); $this->user_model->update_session($decrypted_string); $this->user_model->set_last_login($decrypted_string); - - log_message('debug', '[User ID: '.$decrypted_string.'] Remember Me Login Successful'); - + + log_message('debug', '[User ID: ' . $decrypted_string . '] Remember Me Login Successful'); + redirect('dashboard'); } catch (Exception $e) { // Something went wrong with the cookie @@ -909,33 +939,32 @@ function login() { redirect('user/login'); } } - + if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Login"; $this->load->view('interface_assets/mini_header', $data); $this->load->view('user/login'); $this->load->view('interface_assets/footer'); - } else { - if($this->user_model->login() == 1) { + if ($this->user_model->login() == 1) { $this->session->set_flashdata('notice', 'User logged in'); $this->user_model->update_session($data['user']->user_id); $this->user_model->set_last_login($data['user']->user_id); - $cookie= array( + $cookie = array( 'name' => 'language', 'value' => $data['user']->language, - 'expire' => time()+1000, + 'expire' => time() + 1000, 'secure' => FALSE ); $this->input->set_cookie($cookie); - + // Create a remember me cookie - if($this->input->post('remember_me') == '1') { + if ($this->input->post('remember_me') == '1') { $encrypted_string = $this->encryption->encrypt($data['user']->user_id); - $cookie= array( + $cookie = array( 'name' => 'remember_me', 'value' => $encrypted_string, 'expire' => '1209600', @@ -951,7 +980,8 @@ function login() { } } - function logout() { + function logout() + { $this->load->model('user_model'); $user_name = $this->session->userdata('user_name'); @@ -961,7 +991,7 @@ function logout() { $this->user_model->clear_session(); - $this->session->set_flashdata('notice', 'User '.$user_name.' logged out.'); + $this->session->set_flashdata('notice', 'User ' . $user_name . ' logged out.'); redirect('dashboard'); } @@ -971,7 +1001,8 @@ function logout() { * Allows users to input an email address and a password will be sent to that address. * */ - function forgot_password() { + function forgot_password() + { $this->load->helper(array('form', 'url')); @@ -979,21 +1010,18 @@ function forgot_password() { $this->form_validation->set_rules('email', 'Email', 'required'); - if ($this->form_validation->run() == FALSE) - { + if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Forgot Password"; $this->load->view('interface_assets/mini_header', $data); $this->load->view('user/forgot_password'); $this->load->view('interface_assets/footer'); - } - else - { + } else { // Check email address exists $this->load->model('user_model'); $check_email = $this->user_model->check_email_address($this->input->post('email', true)); - if($check_email == TRUE) { + if ($check_email == TRUE) { // Generate password reset code 50 characters long $this->load->helper('string'); $reset_code = random_string('alnum', 50); @@ -1005,8 +1033,8 @@ function forgot_password() { $this->data['reset_code'] = $reset_code; $this->load->library('email'); - if($this->optionslib->get_option('emailProtocol') == "smtp") { - $config = Array( + if ($this->optionslib->get_option('emailProtocol') == "smtp") { + $config = array( 'protocol' => $this->optionslib->get_option('emailProtocol'), 'smtp_crypto' => $this->optionslib->get_option('smtpEncryption'), 'smtp_host' => $this->optionslib->get_option('smtpHost'), @@ -1015,9 +1043,9 @@ function forgot_password() { 'smtp_pass' => $this->optionslib->get_option('smtpPassword'), 'crlf' => "\r\n", 'newline' => "\r\n" - ); + ); - $this->email->initialize($config); + $this->email->initialize($config); } $message = $this->load->view('email/forgot_password', $this->data, TRUE); @@ -1028,8 +1056,7 @@ function forgot_password() { $this->email->subject('Cloudlog Account Password Reset'); $this->email->message($message); - if (! $this->email->send()) - { + if (!$this->email->send()) { // Redirect to login page with message $this->session->set_flashdata('warning', 'Email settings are incorrect.'); redirect('user/login'); @@ -1047,10 +1074,14 @@ function forgot_password() { } // Send an E-Mail to the user. Function is similar to forgot_password() - function admin_send_passwort_reset() { + function admin_send_passwort_reset() + { $this->load->model('user_model'); - if(!$this->user_model->authorize(99)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); } + if (!$this->user_model->authorize(99)) { + $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); + redirect('dashboard'); + } $query = $this->user_model->get_by_id($this->uri->segment(3)); $this->load->library('form_validation'); @@ -1059,19 +1090,16 @@ function admin_send_passwort_reset() { $data = $query->row(); - if ($this->form_validation->run() != FALSE) - { + if ($this->form_validation->run() != FALSE) { $this->session->set_flashdata('notice', 'Something went wrong! User has no user_id.'); redirect('user'); - } - else - { + } else { // Check email address exists $this->load->model('user_model'); $check_email = $this->user_model->check_email_address($data->user_email); - if($check_email == TRUE) { + if ($check_email == TRUE) { // Generate password reset code 50 characters long $this->load->helper('string'); $reset_code = random_string('alnum', 50); @@ -1085,8 +1113,8 @@ function admin_send_passwort_reset() { $this->data['user_name'] = $data->user_name; $this->load->library('email'); - if($this->optionslib->get_option('emailProtocol') == "smtp") { - $config = Array( + if ($this->optionslib->get_option('emailProtocol') == "smtp") { + $config = array( 'protocol' => $this->optionslib->get_option('emailProtocol'), 'smtp_crypto' => $this->optionslib->get_option('smtpEncryption'), 'smtp_host' => $this->optionslib->get_option('smtpHost'), @@ -1095,9 +1123,9 @@ function admin_send_passwort_reset() { 'smtp_pass' => $this->optionslib->get_option('smtpPassword'), 'crlf' => "\r\n", 'newline' => "\r\n" - ); + ); - $this->email->initialize($config); + $this->email->initialize($config); } $message = $this->load->view('email/admin_reset_password', $this->data, TRUE); @@ -1107,8 +1135,7 @@ function admin_send_passwort_reset() { $this->email->subject('Cloudlog Account Password Reset'); $this->email->message($message); - if (! $this->email->send()) - { + if (!$this->email->send()) { // Redirect to user page with message $this->session->set_flashdata('danger', lang('admin_email_settings_incorrect')); redirect('user'); @@ -1128,7 +1155,7 @@ function admin_send_passwort_reset() { function reset_password($reset_code = NULL) { $data['reset_code'] = $reset_code; - if($reset_code != NULL) { + if ($reset_code != NULL) { $this->load->helper(array('form', 'url')); $this->load->library('form_validation'); @@ -1136,15 +1163,12 @@ function reset_password($reset_code = NULL) $this->form_validation->set_rules('password', 'Password', 'required'); $this->form_validation->set_rules('password_confirm', 'Password Confirmation', 'required|matches[password]'); - if ($this->form_validation->run() == FALSE) - { + if ($this->form_validation->run() == FALSE) { $data['page_title'] = "Reset Password"; $this->load->view('interface_assets/mini_header', $data); $this->load->view('user/reset_password'); $this->load->view('interface_assets/footer'); - } - else - { + } else { // Lets reset the password! $this->load->model('user_model'); @@ -1157,25 +1181,26 @@ function reset_password($reset_code = NULL) } } - function check_locator($grid) { - $grid = $this->input->post('user_locator'); - // Allow empty locator - if (preg_match('/^$/', $grid)) return true; - // Allow 6-digit locator - if (preg_match('/^[A-Ra-r]{2}[0-9]{2}[A-Za-z]{2}$/', $grid)) return true; - // Allow 4-digit locator - else if (preg_match('/^[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; - // Allow 4-digit grid line - else if (preg_match('/^[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; - // Allow 4-digit grid corner - else if (preg_match('/^[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; - // Allow 2-digit locator - else if (preg_match('/^[A-Ra-r]{2}$/', $grid)) return true; - // Allow 8-digit locator - else if (preg_match('/^[A-Ra-r]{2}[0-9]{2}[A-Za-z]{2}[0-9]{2}$/', $grid)) return true; - else { - $this->form_validation->set_message('check_locator', 'Please check value for grid locator ('.strtoupper($grid).').'); - return false; - } - } + function check_locator($grid) + { + $grid = $this->input->post('user_locator'); + // Allow empty locator + if (preg_match('/^$/', $grid)) return true; + // Allow 6-digit locator + if (preg_match('/^[A-Ra-r]{2}[0-9]{2}[A-Za-z]{2}$/', $grid)) return true; + // Allow 4-digit locator + else if (preg_match('/^[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; + // Allow 4-digit grid line + else if (preg_match('/^[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; + // Allow 4-digit grid corner + else if (preg_match('/^[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2},[A-Ra-r]{2}[0-9]{2}$/', $grid)) return true; + // Allow 2-digit locator + else if (preg_match('/^[A-Ra-r]{2}$/', $grid)) return true; + // Allow 8-digit locator + else if (preg_match('/^[A-Ra-r]{2}[0-9]{2}[A-Za-z]{2}[0-9]{2}$/', $grid)) return true; + else { + $this->form_validation->set_message('check_locator', 'Please check value for grid locator (' . strtoupper($grid) . ').'); + return false; + } + } } From c3f8b7be721164ad299e5bbcbdf80c577b1d3385 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Fri, 3 May 2024 16:00:51 +0100 Subject: [PATCH 35/37] [Visitor] Fixed issue where grid map wasnt functional --- application/controllers/Visitor.php | 10 +++++----- application/models/Gridmap_model.php | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/application/controllers/Visitor.php b/application/controllers/Visitor.php index 54bffd672..496ac3e09 100644 --- a/application/controllers/Visitor.php +++ b/application/controllers/Visitor.php @@ -248,7 +248,7 @@ public function satellites() // Get Confirmed LoTW & Paper Squares (non VUCC) - $query = $this->gridmap_model->get_band_confirmed('SAT', 'All', 'false', 'true', 'false', 'All', $logbooks_locations_array); + $query = $this->gridmap_model->get_band_confirmed('SAT', 'All', 'true', 'true', 'false', 'false', 'All', $logbooks_locations_array); if ($query && $query->num_rows() > 0) @@ -284,7 +284,7 @@ public function satellites() } // Get worked squares - $query = $this->gridmap_model->get_band('SAT', 'All', 'false', 'true', 'false', 'All', $logbooks_locations_array); + $query = $this->gridmap_model->get_band('SAT', 'All', 'false', 'true', 'false', 'false', 'All', $logbooks_locations_array); if ($query && $query->num_rows() > 0) { @@ -318,7 +318,7 @@ public function satellites() } } - $query_vucc = $this->gridmap_model->get_band_worked_vucc_squares('SAT', 'All', 'false', 'true', 'false', 'All', $logbooks_locations_array); + $query_vucc = $this->gridmap_model->get_band_worked_vucc_squares('SAT', 'All', 'false', 'true', 'false', 'false', 'All', $logbooks_locations_array); if ($query && $query_vucc->num_rows() > 0) { @@ -341,11 +341,11 @@ public function satellites() array_push($array_grid_4char, $grid_four); } } - } + } } // Confirmed Squares - $query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares('SAT', 'All', 'false', 'true', 'false', 'All', $logbooks_locations_array); + $query_vucc = $this->gridmap_model->get_band_confirmed_vucc_squares('SAT', 'All', 'true', 'true', 'false', 'false', 'All', $logbooks_locations_array); if ($query && $query_vucc->num_rows() > 0) { diff --git a/application/models/Gridmap_model.php b/application/models/Gridmap_model.php index 56047f3bc..6581b37aa 100644 --- a/application/models/Gridmap_model.php +++ b/application/models/Gridmap_model.php @@ -3,6 +3,7 @@ class Gridmap_model extends CI_Model { function get_band_confirmed($band, $mode, $qsl, $lotw, $eqsl, $qrz, $sat, $logbooks_locations_array = NULL) { + if ($logbooks_locations_array == NULL) { $CI =& get_instance(); $CI->load->model('logbooks_model'); From b2168badd959e48b26c62b34e2515e119dff056e Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Sat, 4 May 2024 14:00:57 +0100 Subject: [PATCH 36/37] [API] Add check_auth function with json output --- application/controllers/Api.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/application/controllers/Api.php b/application/controllers/Api.php index 6a9a43408..f1edde378 100644 --- a/application/controllers/Api.php +++ b/application/controllers/Api.php @@ -127,6 +127,29 @@ function auth($key) { } } + function check_auth($key) { + $this->load->model('api_model'); + header("Content-type: text/xml"); + if($this->api_model->access($key) == "No Key Found" || $this->api_model->access($key) == "Key Disabled") { + // set the content type as json + header("Content-type: application/json"); + + // set the http response code to 401 + http_response_code(401); + + // return the json with the status as failed + echo json_encode(['status' => 'failed', 'reason' => "missing or invalid api key"]); + } else { + // set the content type as json + header("Content-type: application/json"); + + // set the http response code to 200 + http_response_code(200); + // return the json + echo json_encode(['status' => 'valid', 'rights' => $this->api_model->access($key)]); + } + } + function station_info($key) { $this->load->model('api_model'); $this->load->model('stations'); From dfae30bcfaa041d917f7871f7eff6f1189b215c2 Mon Sep 17 00:00:00 2001 From: Peter Goodhall Date: Sun, 5 May 2024 13:33:32 +0100 Subject: [PATCH 37/37] tag 2.6.11 --- application/config/migration.php | 2 +- application/migrations/181_tag_2_6_11.php | 30 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 application/migrations/181_tag_2_6_11.php diff --git a/application/config/migration.php b/application/config/migration.php index cba5ee184..ada7ac419 100644 --- a/application/config/migration.php +++ b/application/config/migration.php @@ -22,7 +22,7 @@ | */ -$config['migration_version'] = 180; +$config['migration_version'] = 181; /* |-------------------------------------------------------------------------- diff --git a/application/migrations/181_tag_2_6_11.php b/application/migrations/181_tag_2_6_11.php new file mode 100644 index 000000000..6117b9c01 --- /dev/null +++ b/application/migrations/181_tag_2_6_11.php @@ -0,0 +1,30 @@ +db->where('option_name', 'version'); + $this->db->update('options', array('option_value' => '2.6.11')); + + // Trigger Version Info Dialog + $this->db->where('option_type', 'version_dialog'); + $this->db->where('option_name', 'confirmed'); + $this->db->update('user_options', array('option_value' => 'false')); + + } + + public function down() + { + $this->db->where('option_name', 'version'); + $this->db->update('options', array('option_value' => '2.6.10')); + } +} \ No newline at end of file