Repository: Urban-Analytics-Technology-Platform/poppusher (language: python)

Issue:
Meta Issue: Trialing Dagster
We have agreed to trial [Dagster](https://dagster.io/) to structure the workflow within popgetter. See [meeting notes here](https://hackmd.io/4-rDxn7KTmqIFgeMZcXcOQ)

This issue is to capture all of the different tasks involved in this.

# Exploration

Within that meeting, we committed to trying three use cases for Dagster before committing to migrating all of popgetter to it. These are:

- [x] A pure python based task (example included in #28)
- [x] Something depending on the Geographic Data Science Docker image (See [this example](https://github.com/dabreegster/popgetter/blob/e709e895cc8733177983960f085b180e73d81560/popgetter/assets/us/__init__.py#L198-L211))
- [x] An escape hatch for wrapping some other third-party tasks (using esoteric dependencies). (Likely to be porting the existing england.py code to Dagster, using [Dagster Pipes](https://github.com/dagster-io/dagster/discussions/16319). (See #32).

# Decision

Once completed, we need to agree whether we are content that Dagster offers a good solution to the workflow management need we've identified (both in the HackMD above, and subsequently whilst attempting these three tasks above).

# Subsequent steps

If the choice of Dagster is confirmed, then there are a number of steps we know we will need to undertake. We can record them here for now. Converting them to individual issues and adding more detail can be done once confirmed.

- [ ] Identify examples of best practices (where they exist) for how to use dagster within popgetter (point to existing implementation within popgetter, rather than reinvent the documentation).
- [ ] Create issues for required use-cases where there is no known best practice.
- [ ] Migrate individual countries to Dagster (create a separate issue/PR for each country).
- [ ] Ensure group/prefixes/jobs etc are organised in a way to make useful subsets of the pipeline easily runnable from the commandline (See #20)
- [x] #38
- [ ] Others things...?





Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 5c1db4b..aae2c19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,26 @@ previous_code/us/node_modules
 persist/
 popgetter/cache/
 popgetter.egg-info/
+popgetter.egg-info/*
+popgetter/assets/uk_venv/
+node_modules/
+
+
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..c5e8369
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,806 @@
+{
+  "name": "popgetter",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "mapshaper": "^0.6.47"
+      }
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz",
+      "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz",
+      "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz",
+      "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==",
+      "cpu": [
+        "arm"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz",
+      "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz",
+      "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz",
+      "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@placemarkio/tokml": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@placemarkio/tokml/-/tokml-0.3.3.tgz",
+      "integrity": "sha512-Y6lprxpPfDxLoUyeNcI/vfxMkeWlTjNFvh73zlxfQtZ8TWIj+rmPY99l5wNFVkHQOAwCzLaBXyxULpbtaMGyHQ=="
+    },
+    "node_modules/@tmcw/togeojson": {
+      "version": "5.8.1",
+      "resolved": "https://registry.npmjs.org/@tmcw/togeojson/-/togeojson-5.8.1.tgz",
+      "integrity": "sha512-2YNrbis3l5kS0XrYwiHEZcGwiRp0MJ5CvwGwtMWp2z2tsVlskeec2qgvKHnF0RCwI5GnjrrBOoKsWfndEnd3LA==",
+      "engines": {
+        "node": "*"
+      },
+      "peerDependencies": {
+        "@types/geojson": "*"
+      }
+    },
+    "node_modules/@types/concat-stream": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz",
+      "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/form-data": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
+      "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==",
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/geojson": {
+      "version": "7946.0.13",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz",
+      "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==",
+      "peer": true
+    },
+    "node_modules/@types/node": {
+      "version": "10.17.60",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
+      "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="
+    },
+    "node_modules/@types/qs": {
+      "version": "6.9.10",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz",
+      "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw=="
+    },
+    "node_modules/@xmldom/xmldom": {
+      "version": "0.8.10",
+      "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+      "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/adm-zip": {
+      "version": "0.5.10",
+      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz",
+      "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==",
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/asap": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+      "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz",
+      "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==",
+      "dependencies": {
+        "function-bind": "^1.1.2",
+        "get-intrinsic": "^1.2.1",
+        "set-function-length": "^1.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
+    },
+    "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==",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.0.0.tgz",
+      "integrity": "sha512-ovx/7NkTrnPuIV8sqk/GjUIIM1+iUQeqA3ye2VNpq9sVoiZsooObWlQy+OPWGI17GDaEoybuAGJm6U8yC077BA==",
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/concat-stream": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+      "engines": [
+        "node >= 0.8"
+      ],
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^2.2.2",
+        "typedarray": "^0.0.6"
+      }
+    },
+    "node_modules/cookies": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz",
+      "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==",
+      "dependencies": {
+        "depd": "~2.0.0",
+        "keygrip": "~1.1.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+    },
+    "node_modules/d3-color": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+      "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-interpolate": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+      "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+      "dependencies": {
+        "d3-color": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/d3-scale-chromatic": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz",
+      "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==",
+      "dependencies": {
+        "d3-color": "1 - 3",
+        "d3-interpolate": "1 - 3"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/define-data-property": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
+      "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
+      "dependencies": {
+        "get-intrinsic": "^1.2.1",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/delaunator": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz",
+      "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==",
+      "dependencies": {
+        "robust-predicates": "^3.0.0"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/fflate": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+      "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw=="
+    },
+    "node_modules/flatbush": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/flatbush/-/flatbush-3.3.1.tgz",
+      "integrity": "sha512-oKuPbtT+DS2CxH+9Vhbsq8HifmSCuOw+3Cy5zt/vCIrZl5KyengoTHDBLmtpZoBhcwa7/biNjgL1DwdLMJYm1A==",
+      "dependencies": {
+        "flatqueue": "^1.2.1"
+      }
+    },
+    "node_modules/flatqueue": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/flatqueue/-/flatqueue-1.2.1.tgz",
+      "integrity": "sha512-X86TpWS1rGuY7m382HuA9vngLeDuWA9lJvhEG+GfgKMV5onSvx5a71cl7GMbXzhWtlN9dGfqOBrpfqeOtUfGYQ=="
+    },
+    "node_modules/form-data": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+      "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 0.12"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+      "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/geographiclib": {
+      "version": "1.48.0",
+      "resolved": "https://registry.npmjs.org/geographiclib/-/geographiclib-1.48.0.tgz",
+      "integrity": "sha512-WIpDKKj2Gu+E4jkF3f3fg7OPF6T1/35tQXKc4jLLQrwjNiTZ5KrrYF5Gp0dQ/YbJIoCjb9vs2/abWTRsCEoi2w==",
+      "deprecated": "This package has been split into geographic-geodesic + geographiclib-dms; use one or both of these instead of geographiclib."
+    },
+    "node_modules/geokdbush": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/geokdbush/-/geokdbush-1.1.0.tgz",
+      "integrity": "sha512-pyyrGCMXZwWJaGt1YZIgGQg5ol3JjvEKESTon10HxdfWXlaqh5An8fNJkwOYUE+VkQfCdvYQKPVezTQU9AqWAA==",
+      "dependencies": {
+        "tinyqueue": "^1.2.2"
+      }
+    },
+    "node_modules/geokdbush/node_modules/tinyqueue": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-1.2.3.tgz",
+      "integrity": "sha512-Qz9RgWuO9l8lT+Y9xvbzhPT2efIUIFd69N7eF7tJ9lnQl0iLj1M7peK7IoUGZL9DJHw9XftqLreccfxcQgYLxA=="
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz",
+      "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==",
+      "dependencies": {
+        "function-bind": "^1.1.2",
+        "has-proto": "^1.0.1",
+        "has-symbols": "^1.0.3",
+        "hasown": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-port": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
+      "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+      "dependencies": {
+        "get-intrinsic": "^1.1.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-property-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz",
+      "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==",
+      "dependencies": {
+        "get-intrinsic": "^1.2.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-proto": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/hasown": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
+      "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
+      "dependencies": {
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/http-basic": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-6.0.0.tgz",
+      "integrity": "sha512-7ScbVjuiReYe8S+OZOpNjoKGXrbhJHIrQQe7eq1TpLTJkxH8MPKvnTUzq/TNLjww1hdFQy8yUIC42wuLhCjYcQ==",
+      "dependencies": {
+        "@types/concat-stream": "^1.6.0",
+        "@types/node": "^7.0.31",
+        "caseless": "~0.12.0",
+        "concat-stream": "^1.4.6",
+        "http-response-object": "^3.0.1",
+        "parse-cache-control": "^1.0.1"
+      }
+    },
+    "node_modules/http-basic/node_modules/@types/node": {
+      "version": "7.10.14",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-7.10.14.tgz",
+      "integrity": "sha512-29GS75BE8asnTno3yB6ubOJOO0FboExEqNJy4bpz0GSmW/8wPTNL4h9h63c6s1uTrOopCmJYe/4yJLh5r92ZUA=="
+    },
+    "node_modules/http-response-object": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
+      "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
+      "dependencies": {
+        "@types/node": "^10.0.3"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/idb-keyval": {
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz",
+      "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg=="
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/is-wsl": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
+      "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+    },
+    "node_modules/kdbush": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz",
+      "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew=="
+    },
+    "node_modules/keygrip": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
+      "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
+      "dependencies": {
+        "tsscmp": "1.0.6"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mapshaper": {
+      "version": "0.6.47",
+      "resolved": "https://registry.npmjs.org/mapshaper/-/mapshaper-0.6.47.tgz",
+      "integrity": "sha512-bdZZr9yheB8M8Q1OYFfuaC51g2gSUQ7H2ckBh98fsjSveY/TzqE0mG9DOudLjEynPdd+aNtWTScTKHo6dXDBbA==",
+      "dependencies": {
+        "@placemarkio/tokml": "^0.3.3",
+        "@tmcw/togeojson": "^5.6.0",
+        "@xmldom/xmldom": "^0.8.6",
+        "adm-zip": "^0.5.9",
+        "commander": "7.0.0",
+        "cookies": "^0.8.0",
+        "d3-color": "3.1.0",
+        "d3-interpolate": "^3.0.1",
+        "d3-scale-chromatic": "3.0.0",
+        "delaunator": "^5.0.0",
+        "fflate": "^0.7.4",
+        "flatbush": "^3.2.1",
+        "geokdbush": "^1.1.0",
+        "iconv-lite": "^0.6.3",
+        "idb-keyval": "^6.2.0",
+        "kdbush": "^3.0.0",
+        "mproj": "0.0.37",
+        "msgpackr": "^1.8.5",
+        "opn": "^5.3.0",
+        "rw": "~1.3.3",
+        "sync-request": "5.0.0",
+        "tinyqueue": "^2.0.3"
+      },
+      "bin": {
+        "mapshaper": "bin/mapshaper",
+        "mapshaper-gui": "bin/mapshaper-gui",
+        "mapshaper-xl": "bin/mapshaper-xl"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "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==",
+      "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==",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mproj": {
+      "version": "0.0.37",
+      "resolved": "https://registry.npmjs.org/mproj/-/mproj-0.0.37.tgz",
+      "integrity": "sha512-UtLQa2UyFQJuwqpLWd6TF3xYNE7nGTQWvwtXHBdpEAn8F/QHP1yTjqvo2CaQem9LcSQoiZLCHP1fRU4uCWzBVw==",
+      "dependencies": {
+        "geographiclib": "1.48.0",
+        "rw": "~1.3.2"
+      },
+      "bin": {
+        "mcs2cs": "bin/mcs2cs",
+        "mproj": "bin/mproj"
+      },
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/msgpackr": {
+      "version": "1.9.9",
+      "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.9.tgz",
+      "integrity": "sha512-sbn6mioS2w0lq1O6PpGtsv6Gy8roWM+o3o4Sqjd6DudrL/nOugY+KyJUimoWzHnf9OkO0T6broHFnYE/R05t9A==",
+      "optionalDependencies": {
+        "msgpackr-extract": "^3.0.2"
+      }
+    },
+    "node_modules/msgpackr-extract": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz",
+      "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==",
+      "hasInstallScript": true,
+      "optional": true,
+      "dependencies": {
+        "node-gyp-build-optional-packages": "5.0.7"
+      },
+      "bin": {
+        "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+      },
+      "optionalDependencies": {
+        "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2",
+        "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2",
+        "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2",
+        "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2",
+        "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2"
+      }
+    },
+    "node_modules/node-gyp-build-optional-packages": {
+      "version": "5.0.7",
+      "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz",
+      "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==",
+      "optional": true,
+      "bin": {
+        "node-gyp-build-optional-packages": "bin.js",
+        "node-gyp-build-optional-packages-optional": "optional.js",
+        "node-gyp-build-optional-packages-test": "build-test.js"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.1",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+      "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/opn": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
+      "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
+      "dependencies": {
+        "is-wsl": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/parse-cache-control": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
+      "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+    },
+    "node_modules/promise": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
+      "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==",
+      "dependencies": {
+        "asap": "~2.0.6"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.11.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
+      "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/robust-predicates": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
+      "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg=="
+    },
+    "node_modules/rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "node_modules/set-function-length": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
+      "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
+      "dependencies": {
+        "define-data-property": "^1.1.1",
+        "get-intrinsic": "^1.2.1",
+        "gopd": "^1.0.1",
+        "has-property-descriptors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/sync-request": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-5.0.0.tgz",
+      "integrity": "sha512-NKhEA4WacR3mRBIFz1niXrIUTrUVFtP2spzrLMINangebvJ/EFyVv+LMJKvVl6UIrJM4Fburnnj91lRnqb4WkA==",
+      "dependencies": {
+        "http-response-object": "^3.0.1",
+        "sync-rpc": "^1.2.0",
+        "then-request": "^5.0.0"
+      }
+    },
+    "node_modules/sync-rpc": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
+      "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
+      "dependencies": {
+        "get-port": "^3.1.0"
+      }
+    },
+    "node_modules/then-request": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/then-request/-/then-request-5.0.0.tgz",
+      "integrity": "sha512-A3uIVLD33SAvB10PfsxLuQBMV8GVC/6xKBMPOvkJchi6251e5AMJ+Yy+RVKsVsnj0iYNhN2E5SkNSi58H19wsw==",
+      "dependencies": {
+        "@types/concat-stream": "^1.6.0",
+        "@types/form-data": "0.0.33",
+        "@types/node": "^8.0.0",
+        "@types/qs": "^6.2.31",
+        "caseless": "~0.12.0",
+        "concat-stream": "^1.6.0",
+        "form-data": "^2.2.0",
+        "http-basic": "^6.0.0",
+        "http-response-object": "^3.0.1",
+        "promise": "^8.0.0",
+        "qs": "^6.4.0"
+      }
+    },
+    "node_modules/then-request/node_modules/@types/node": {
+      "version": "8.10.66",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
+      "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw=="
+    },
+    "node_modules/tinyqueue": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
+      "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA=="
+    },
+    "node_modules/tsscmp": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
+      "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
+      "engines": {
+        "node": ">=0.6.x"
+      }
+    },
+    "node_modules/typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..1dc670e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "mapshaper": "^0.6.47"
+  }
+}
diff --git a/popgetter.egg-info/SOURCES.txt b/popgetter.egg-info/SOURCES.txt
deleted file mode 100644
index e932c1c..0000000
--- a/popgetter.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-LICENSE
-README.md
-pyproject.toml
-setup.cfg
-setup.py
-popgetter/__init__.py
-popgetter.egg-info/PKG-INFO
-popgetter.egg-info/SOURCES.txt
-popgetter.egg-info/dependency_links.txt
-popgetter.egg-info/requires.txt
-popgetter.egg-info/top_level.txt
-popgetter/assets/__init__.py
-popgetter/assets/singapore/__init__.py
-popgetter/assets/us/__init__.py
-popgetter/assets/us/config.py
\ No newline at end of file
diff --git a/popgetter/__init__.py b/popgetter/__init__.py
index 2802576..879012e 100644
--- a/popgetter/__init__.py
+++ b/popgetter/__init__.py
@@ -3,7 +3,8 @@
     Definitions,
     define_asset_job,
     ScheduleDefinition,
-    AssetSelection
+    AssetSelection,
+    PipesSubprocessClient
 )
 
 from popgetter import assets
@@ -12,6 +13,7 @@
 all_assets = [
     *load_assets_from_package_module(assets.us, group_name="us"),
     *load_assets_from_package_module(assets.be, group_name="be"),
+    *load_assets_from_package_module(assets.uk, group_name="uk"),
 ]
 
 job_be = define_asset_job(
@@ -26,9 +28,15 @@
     description="Downloads USA data.",
 )
 
+job_uk = define_asset_job(
+    name="job_uk",
+    selection=AssetSelection.groups("uk"),
+    description="Downloads UK data.",
+)
+
 defs = Definitions(
     assets=all_assets,
     schedules=[],
-    resources={},
-    jobs=[job_be, job_us],
+    resources={"pipes_subprocess_client": PipesSubprocessClient()},
+    jobs=[job_be, job_us, job_uk],
 )
diff --git a/popgetter/assets/__init__.py b/popgetter/assets/__init__.py
index 930e8df..950ee1a 100644
--- a/popgetter/assets/__init__.py
+++ b/popgetter/assets/__init__.py
@@ -1,1 +1,1 @@
-from . import us, be
+from . import us, be, uk
diff --git a/popgetter/assets/uk/__init__.py b/popgetter/assets/uk/__init__.py
new file mode 100644
index 0000000..c300a5b
--- /dev/null
+++ b/popgetter/assets/uk/__init__.py
@@ -0,0 +1,94 @@
+import shutil
+import popgetter
+from pathlib import Path
+import os
+
+from dagster import (
+    AssetExecutionContext,
+    MaterializeResult,
+    PipesSubprocessClient,
+    asset,
+    file_relative_path,
+)
+
+
+uk_venv_path = str((Path(__file__).parent.parent / "uk_venv").absolute())
+
+@asset(key_prefix="uk", name="create_custom_venv")
+def create_custom_venv(
+    context: AssetExecutionContext,
+    pipes_subprocess_client: PipesSubprocessClient,
+) -> MaterializeResult:
+    context.log.info(f"Creating custom venv for UK at {uk_venv_path}")
+    context.add_output_metadata(
+        metadata={
+            "uk_venv_path": uk_venv_path,
+            "python_version": shutil.which("python"),
+        }
+    )
+    cmd = [shutil.which("python"), "-m", "venv", uk_venv_path]
+
+    pcci = pipes_subprocess_client.run(
+        command=cmd, context=context
+    )
+    context.log.debug(f"pcci: {pcci}")
+    context.log.debug(f"dir(pcci): {dir(pcci)}")
+    # return pcci.get_results()
+
+    py_exe = str(Path(uk_venv_path) / "bin" / "python")
+    context.log.info(f"Installing custom dependencies for UK at {uk_venv_path}")
+    context.add_output_metadata(
+        metadata={
+            "py_exe": py_exe,
+            "python_version": shutil.which("python"),
+        }
+    )
+    cmd = [py_exe, "-m", "pip", "install", "-r", file_relative_path(__file__, "requirements-non-foss-uk.txt")] 
+    pcci = pipes_subprocess_client.run(
+        command=cmd, context=context
+    )
+    context.log.debug(f"pcci: {pcci}")
+    context.log.debug(f"dir(pcci): {dir(pcci)}")
+    return pcci.get_results()
+
+
+
+@asset(key_prefix="uk", name="install_mapshaper")
+def install_mapshaper(
+    context: AssetExecutionContext,
+    pipes_subprocess_client: PipesSubprocessClient,
+) -> MaterializeResult:
+    """
+    Assumption: `npm` is installed and on the path.
+    """
+    context.log.info(f"Installing Mapshaper")
+
+    cmd = [shutil.which("npm"), "install", "mapshaper"]
+    context.log.info(f"cmd: {cmd}")
+
+    pcci = pipes_subprocess_client.run(
+        command=cmd, context=context, env={"PATH": os.environ["PATH"]}
+    )
+
+    context.log.debug(f"pcci: {pcci}")
+    context.log.debug(f"dir(pcci): {dir(pcci)}")
+    result = pcci.get_results()
+    context.log.debug(f"result: {result}")
+    context.log.debug(f"dir(result): {dir(result)}")
+    return result
+
+
+@asset(
+    key_prefix="uk",
+    name="legacy_asset",
+    deps=[create_custom_venv, install_mapshaper],
+)
+def legacy_asset(
+    context: AssetExecutionContext, pipes_subprocess_client: PipesSubprocessClient
+) -> MaterializeResult:
+    py_exe = str(Path(uk_venv_path) / "bin" / "python")
+    cmd = [py_exe, file_relative_path(__file__, "legacy/england.py")]
+    return pipes_subprocess_client.run(
+        command=cmd, context=context, env={"PATH": os.environ["PATH"]}
+    ).get_results()
+
diff --git a/previous_code/downloader.py b/popgetter/assets/uk/legacy/downloader.py
similarity index 100%
rename from previous_code/downloader.py
rename to popgetter/assets/uk/legacy/downloader.py
diff --git a/previous_code/england.py b/popgetter/assets/uk/legacy/england.py
similarity index 82%
rename from previous_code/england.py
rename to popgetter/assets/uk/legacy/england.py
index 4ad017c..301f0c6 100755
--- a/previous_code/england.py
+++ b/popgetter/assets/uk/legacy/england.py
@@ -7,6 +7,12 @@
 import subprocess
 from downloader import download_from_arcgis_online
 
+import pandas as pd
+# import geopandas as gpd
+from dagster_pipes import PipesContext, PipesMetadataValue, open_dagster_pipes
+
+open_dagster_pipes()
+
 
 def convert_geo_to_topo_json(geojson_file, topojson_file, new_layer_name, working_dir):
     """
@@ -67,7 +73,6 @@ def join_vehicle_ownership(output_areas_topojson_path, census_path, output_path)
 if __name__ == "__main__":
     WORKING_DIR = "data"
 
-    # Output Areas
 
     # Ideally we would use the Output Areas as served by the ONS:
     # OUTPUT_AREAS_URL = "https://services1.arcgis.com/ESMARspQHYMw9BZ9/arcgis/rest/services/Output_Areas_Dec_2021_Boundaries_Generalised_Clipped_EW_BGC_2022/FeatureServer/"
@@ -95,3 +100,18 @@ def join_vehicle_ownership(output_areas_topojson_path, census_path, output_path)
 
     download_vehicle_ownership(CENSUS_URL, WORKING_DIR)
     join_vehicle_ownership(output_areas_topojson_path, census_path, combined_output_path)
+
+    # Report back to Dagster (if running in Dagster)
+    context = PipesContext.get()
+    assert context.asset_key # things like asset key are passed automatically and available in context
+    # context.report_asset_materialization(metadata={"nrows": nrows}) # nrows was defined somewhere in the script
+
+    census_df = pd.read_csv(census_path)
+
+    context.report_asset_materialization(
+        metadata={
+            "census_num_records": len(census_df),  # Metadata can be any key-value pair
+            "census_columns": PipesMetadataValue(type="md", raw_value="\n".join([f"- '`{col}`'" for col in  census_df.columns.to_list()])),
+            "census_preview": PipesMetadataValue(type="md", raw_value=census_df.head().to_csv()),
+        }
+    ) 
diff --git a/popgetter/assets/uk/requirements-non-foss-uk.txt b/popgetter/assets/uk/requirements-non-foss-uk.txt
new file mode 100644
index 0000000..d2e9af7
--- /dev/null
+++ b/popgetter/assets/uk/requirements-non-foss-uk.txt
@@ -0,0 +1,2 @@
+arcgis~=2.0.0
+dagster-pipes
diff --git a/previous_code/requirements-non-foss.txt b/previous_code/requirements-non-foss.txt
deleted file mode 100644
index 7b892a4..0000000
--- a/previous_code/requirements-non-foss.txt
+++ /dev/null
@@ -1,1 +0,0 @@
-arcgis~=2.0.0
\ No newline at end of file


Test patch:
diff --git a/popgetter_tests/uk.py b/popgetter_tests/uk.py
new file mode 100644
index 0000000..791544e
--- /dev/null
+++ b/popgetter_tests/uk.py
@@ -0,0 +1,2 @@
+from popgetter.assets import uk
+