From ec2720d782f23b03349f585b44f259eb007d9088 Mon Sep 17 00:00:00 2001 From: Bob Clough Date: Mon, 13 Oct 2025 15:51:19 +0100 Subject: [PATCH 1/5] maybe fix mk4 page --- TiLDA_MK4.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/TiLDA_MK4.md b/TiLDA_MK4.md index 7b5883c..7a7bd69 100644 --- a/TiLDA_MK4.md +++ b/TiLDA_MK4.md @@ -106,16 +106,13 @@ messages with the "sms" app. You can also answer calls by pressing "Call" in any app, and end or reject a call using the "End" button at any time. - The cellular part of the badge seems to work (reliably) +The cellular part of the badge seems to work (reliably) perfectly if an external antenna is used, such as a mag-mount with a length of coax. Seems to be an EMC issue, as using the pictured right angle antenna directly on the SMA does not work reliably. Time to get the Kapton tape and copper foil out... -
-
File:GSM Antenna.jpg
-
### Connecting over USB @@ -153,9 +150,9 @@ On Windows: 3. Change COM1 to the COM port for your badge (You can usually find this as USB Seiral Port under ports in device manager) -Note: if your badge resets while putty is open, +Note: if your badge resets while putty is open, you will have to close the window and open a new connection to the same -COM port. +COM port. The basic process is this: @@ -286,7 +283,7 @@ SerialTimeoutException: Write Timeout Fix: **Using the Grove Serial connector** - The Badge Team thoughtfully chose to include a couple of +The Badge Team thoughtfully chose to include a couple of Seeed Studio Grove system connectors to the 2018 badge. Looking at the rear of the badge, they are either side of the unpopulated 3.5mm jack footprint, top right. @@ -402,4 +399,4 @@ Hardware files are available on GitHub ![](Sensor_graphic_-_with_fixed_transparency-02.png "Sensor_graphic_-_with_fixed_transparency-02.png") Category: Badges \ No newline at end of file +title="Category: Badges">Category: Badges From d50ad61594f386decc7741becd3dddbc46b5027e Mon Sep 17 00:00:00 2001 From: Bob Clough Date: Mon, 13 Oct 2025 16:21:41 +0100 Subject: [PATCH 2/5] Fix (?) front page --- index.md | 93 ++++++++++++-------------------------------------------- 1 file changed, 20 insertions(+), 73 deletions(-) diff --git a/index.md b/index.md index 213fdb4..8f4f322 100644 --- a/index.md +++ b/index.md @@ -2,12 +2,6 @@ The aim of the EMF badge is to give people interesting hardware they've probably not experimented with before while being simple enough that anyone can play with it. -
- -__TOC__ - -
- ## Contacting the badge team - email: **badge@emfcamp.org** @@ -29,61 +23,34 @@ badge](https://blog.emfcamp.org/2024/03/18/tildagon/)** ## EMF2022 - TiDAL -**TiDAL documentation main page.** - -**[App store hatchery](https://2022.badge.emfcamp.org).** +- [Documentation mainpage](https://github.com/emfcamp/tidal-docs) +- [Firmare Repository](https://github.com/emfcamp/TiDAL-Firmware) +- [Hardware Repository](https://github.com/emfcamp/TiDAL-Hardware) +- [Flyer](https://usercontent.irccloud-cdn.com/file/tRv4Lyv4/badge+flyer.pdf) +- [App store](https://2022.badge.emfcamp.org) ## EMF2018 - TiLDA Mkδ -
- -
TiLDA_Mk4_Front_with_sponsors.png
-
- -**TiLDA -Mkδ main page.** - -2018 badge announcement on our blog - +![Mk4 Front with sponsors](TiLDA_Mk4_Front_with_sponsors.png "Mk4 Front with sponsors") -
- -
+[TiLDA Mkδ main page](TiLDA_MK4) +[2018 badge announcement on our blog](http://blog.emfcamp.org/post/177423823788/tilda-mk4-the-emf-2018-badge) ## EMF2016 - TiLDA Mkπ -
- -
TiLDA_MK3_front.jpg
-
- -TiLDA_MK3 -main page. - -2016 badge announcement on our blog - - -Update, we have sponsors, the badge is saved! - - +![Mk3 Front](TiLDA_MK3_front.jpg) -
+[TiLDA MK3 main page](TiLDA_MK3) -
+[2016 badge announcement on our blog] +(http://blog.emfcamp.org/post/144514906298/tilda-mkπ-the-hackable-conference-badge-that) +[2016 badge sponsor update](http://blog.emfcamp.org/post/145667126793/the-emf-tilda-badge-is-saved) ## EMF2014 - TiLDA MKe -
- -
Tumblr_inline_n9znh3W5tC1rpuop0.jpg
-
+![Mk2 Front](Tumblr_inline_n9znh3W5tC1rpuop0.jpg) -The -TiLDA MKe -project is code named "ElectroMagnetic Boogaloo" +The [TiLDA MKe project](TiLDA_MKe) is code named "ElectroMagnetic Boogaloo" The MKe is an entirely new design, based on the Arduino Due. It brings an LCD display, Accelerometer and Gyro, along with a long-range wireless @@ -95,19 +62,15 @@ Please Note: There are a couple of minor hardware and some firmware issues with the MKe that might be effecting your badge. If you've let the magic smoke out of your charge controller or have tried to re-flash and ended up with nothing but a couple of dimly glowing lights then DO -NOT DESPAIR -It's recoverable and fixes, documentation and lots of +NOT DESPAIR - It's recoverable and fixes, documentation and lots of firmware are still being produced :) -
+## EMW2013 - SiNE -
+![SiNE Front](800px-SiNE_Front_Angle.JPG "800px-SiNE_Front_Angle.JPG") -## EMW2013 - SiNE -![](800px-SiNE_Front_Angle.JPG "800px-SiNE_Front_Angle.JPG") -SiNE: Investigating -the Neighbourhood of EMW +[SiNE: Investigating the Neighbourhood of EMW](SiNE) Each attendee of Electromagnetic Wave received a SiNE badge, allowing them to take part in a treasure hunt based around the boat. By solving @@ -118,28 +81,12 @@ stored at each location. Holding your badge in front of the letter lit the corresponding light on a badge, allowing the user to collect them all! -
- -
- ## EMF2012 - TiLDA MK1 ![](Emf2012_badge_pcb.png "Emf2012_badge_pcb.png") + [TiLDA](http://wiki-archive.emfcamp.org/2012/articles/b/a/d/Badge.html) The first EMF camp badge, base around the Arduino Leonard, with on board IR, NRF24 Radio and RGB LED's. [Revealing TiLDA, our camp badge!](http://blog.emfcamp.org/post/28558155390/revealing-tilda-our-camp-badge) - -
- -
- -## Badge Team - -The badge team is being headed by - -- 'RepRap' Matt from Nottinghack -- Bob from - Hackspace Manchester \ No newline at end of file From 7fef03dab0f2a2c63f132268f435a7358e80956f Mon Sep 17 00:00:00 2001 From: Bob Clough Date: Mon, 13 Oct 2025 17:01:23 +0100 Subject: [PATCH 3/5] WIP: Move to mkdocs --- .gitignore | 1 + .python-version | 1 + CI.yml | 51 + README.md | 0 TiLDA_MK3(1).md | 2 - SiNE.md => docs/SiNE.md | 8 +- TiDAL.md => docs/TiDAL.md | 0 .../TiLDA_MK3}/App_Store_Submissions.md | 0 .../TiLDA_MK3/Badge16_Ideas.md | 0 .../TiLDA_MK3/Badge_Competition_2016.md | 0 .../TiLDA_MK3}/Firmware_Update.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/Get_Started.md | 0 .../TiLDA_MK3}/How_to_fix_NeoPixel.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/Ideas.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/Ideas/hab.md | 0 .../Introduction_to_badge_hacking.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/NeoPixel.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/Run_Code.md | 0 .../TiLDA_MK3/TiLDA_MK3_API.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/adc.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/apps.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/apps/nmap.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/build.md | 0 TiLDA_MK3.md => docs/TiLDA_MK3/index.md | 2 +- .../TiLDA_MK3}/memory_problems.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/modtilda.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/reset.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/rtc.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/spi.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/subtree.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/timer.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/ugfx.md | 0 {TiLDA_MK3 => docs/TiLDA_MK3}/wifi.md | 0 .../TiLDA_MK4}/Badge_Store_Submissions.md | 0 .../TiLDA_MK4}/BuildingFirmware.md | 0 .../TiLDA_MK4}/Code_Structure.md | 0 .../TiLDA_MK4}/Firmware_Update(1).md | 0 .../TiLDA_MK4}/Get_Started(1).md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/Neopix.md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/Run_Code(1).md | 0 TiLDA_MK4.md => docs/TiLDA_MK4/index.md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/modtilda(1).md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/reset(1).md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/sensors.md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/sim800.md | 0 .../TiLDA_MK4}/sim800/Reverse_engineering.md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/tilda-tools.md | 0 {TiLDA_MK4 => docs/TiLDA_MK4}/ugfx(1).md | 0 {TiLDA_MKe => docs/TiLDA_MKe}/FreeRTOS.md | 0 .../TiLDA_MKe}/Full_Specification.md | 0 TiLDA_MKe.md => docs/TiLDA_MKe/index.md | 28 +- {UHB-IF => docs/UHB-IF}/Issued_IDs.md | 0 {UHB-IF => docs/UHB-IF}/Uncontrolled_IDs.md | 0 UHB-IF.md => docs/UHB-IF/index.md | 0 .../images/800px-SiNE_Front_Angle.jpeg | Bin Badge_Back.png => docs/images/Badge_Back.png | Bin .../images/Badge_Front.png | Bin .../images/EMF_Badge_Antenna_Mod.jpg | Bin .../images/GSM_Antenna.jpg | Bin ...ClTQDH_p.554927_1470307053798_P1010517.jpg | Bin ...ClTQDH_p.554927_1470307470838_P1010533.jpg | Bin ...lTQDH_p.554927_1470420913282_legbender.jpg | Bin IMG_0474.jpg => docs/images/IMG_0474.jpg | Bin ...r_graphic_-_with_fixed_transparency-01.png | Bin ...r_graphic_-_with_fixed_transparency-02.png | Bin .../images/Sheild_Headers.jpeg | Bin .../images/TiLDA_MK3_front.jpg | Bin .../images/TiLDA_Mk4_Front_with_sponsors.png | Bin Tilda_MKe.jpg => docs/images/Tilda_MKe.jpg | Bin .../Tumblr_inline_n9znh3W5tC1rpuop0.jpg | Bin pinout-1.png => docs/images/pinout-1.png | Bin pinout2-1.png => docs/images/pinout2-1.png | Bin index.md => docs/index.md | 5 +- main.py | 6 + mediawiki_export/EMF+Badge-20250904133600.xml | 4919 ----------------- mkdocs.yml | 57 + pyproject.toml | 7 + uv.lock | 8 + 78 files changed, 145 insertions(+), 4950 deletions(-) create mode 100644 .gitignore create mode 100644 .python-version create mode 100644 CI.yml create mode 100644 README.md delete mode 100644 TiLDA_MK3(1).md rename SiNE.md => docs/SiNE.md (96%) rename TiDAL.md => docs/TiDAL.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/App_Store_Submissions.md (100%) rename Badge16_Ideas.md => docs/TiLDA_MK3/Badge16_Ideas.md (100%) rename Badge_Competition_2016.md => docs/TiLDA_MK3/Badge_Competition_2016.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Firmware_Update.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Get_Started.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/How_to_fix_NeoPixel.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Ideas.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Ideas/hab.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Introduction_to_badge_hacking.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/NeoPixel.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/Run_Code.md (100%) rename TiLDA_MK3_API.md => docs/TiLDA_MK3/TiLDA_MK3_API.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/adc.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/apps.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/apps/nmap.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/build.md (100%) rename TiLDA_MK3.md => docs/TiLDA_MK3/index.md (99%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/memory_problems.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/modtilda.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/reset.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/rtc.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/spi.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/subtree.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/timer.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/ugfx.md (100%) rename {TiLDA_MK3 => docs/TiLDA_MK3}/wifi.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Badge_Store_Submissions.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/BuildingFirmware.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Code_Structure.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Firmware_Update(1).md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Get_Started(1).md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Neopix.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/Run_Code(1).md (100%) rename TiLDA_MK4.md => docs/TiLDA_MK4/index.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/modtilda(1).md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/reset(1).md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/sensors.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/sim800.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/sim800/Reverse_engineering.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/tilda-tools.md (100%) rename {TiLDA_MK4 => docs/TiLDA_MK4}/ugfx(1).md (100%) rename {TiLDA_MKe => docs/TiLDA_MKe}/FreeRTOS.md (100%) rename {TiLDA_MKe => docs/TiLDA_MKe}/Full_Specification.md (100%) rename TiLDA_MKe.md => docs/TiLDA_MKe/index.md (91%) rename {UHB-IF => docs/UHB-IF}/Issued_IDs.md (100%) rename {UHB-IF => docs/UHB-IF}/Uncontrolled_IDs.md (100%) rename UHB-IF.md => docs/UHB-IF/index.md (100%) rename 800px-SiNE_Front_Angle.jpeg => docs/images/800px-SiNE_Front_Angle.jpeg (100%) rename Badge_Back.png => docs/images/Badge_Back.png (100%) rename Badge_Front.png => docs/images/Badge_Front.png (100%) rename EMF_Badge_Antenna_Mod.jpg => docs/images/EMF_Badge_Antenna_Mod.jpg (100%) rename GSM_Antenna.jpg => docs/images/GSM_Antenna.jpg (100%) rename Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg => docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg (100%) rename Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg => docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg (100%) rename Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg => docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg (100%) rename IMG_0474.jpg => docs/images/IMG_0474.jpg (100%) rename Sensor_graphic_-_with_fixed_transparency-01.png => docs/images/Sensor_graphic_-_with_fixed_transparency-01.png (100%) rename Sensor_graphic_-_with_fixed_transparency-02.png => docs/images/Sensor_graphic_-_with_fixed_transparency-02.png (100%) rename Sheild_Headers.jpeg => docs/images/Sheild_Headers.jpeg (100%) rename TiLDA_MK3_front.jpg => docs/images/TiLDA_MK3_front.jpg (100%) rename TiLDA_Mk4_Front_with_sponsors.png => docs/images/TiLDA_Mk4_Front_with_sponsors.png (100%) rename Tilda_MKe.jpg => docs/images/Tilda_MKe.jpg (100%) rename Tumblr_inline_n9znh3W5tC1rpuop0.jpg => docs/images/Tumblr_inline_n9znh3W5tC1rpuop0.jpg (100%) rename pinout-1.png => docs/images/pinout-1.png (100%) rename pinout2-1.png => docs/images/pinout2-1.png (100%) rename index.md => docs/index.md (97%) create mode 100644 main.py delete mode 100644 mediawiki_export/EMF+Badge-20250904133600.xml create mode 100644 mkdocs.yml create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..16d3c4d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.cache diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..2c07333 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11 diff --git a/CI.yml b/CI.yml new file mode 100644 index 0000000..1f47471 --- /dev/null +++ b/CI.yml @@ -0,0 +1,51 @@ +name: CI +on: + push: + branches: + - main + pull_request: {} +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set up Python" + uses: actions/setup-python@v5 + with: + python-version-file: "pyproject.toml" + - name: Install uv + uses: astral-sh/setup-uv@v6 + - name: Install the project + run: uv sync --locked --all-extras --dev + - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - uses: actions/cache@v4 + with: + key: mkdocs-material-${{ env.cache_id }} + path: .cache + restore-keys: | + mkdocs-material- + - name: Build docs + env: + CI: ${{ github.ref == 'refs/heads/main' }} + run: pipenv run mkdocs build + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: site/ + deploy: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + needs: build + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/TiLDA_MK3(1).md b/TiLDA_MK3(1).md deleted file mode 100644 index c5ac0d2..0000000 --- a/TiLDA_MK3(1).md +++ /dev/null @@ -1,2 +0,0 @@ -You are looking for the root page; -TiLDA_MK3. \ No newline at end of file diff --git a/SiNE.md b/docs/SiNE.md similarity index 96% rename from SiNE.md rename to docs/SiNE.md index 49ec07b..30468aa 100644 --- a/SiNE.md +++ b/docs/SiNE.md @@ -1,8 +1,4 @@ -
- -
800px-SiNE_Front_Angle.JPG
-
+![](/images/800px-SiNE_Front_Angle.JPG "SiNE Front Angle") ## About SiNE @@ -154,4 +150,4 @@ The following parts were used: (data-sheet links to come) - [Firmware](https://github.com/EMF-TiLDA/SiNE-Firmware) Category:Badges \ No newline at end of file +title="Category:Badges">Category:Badges diff --git a/TiDAL.md b/docs/TiDAL.md similarity index 100% rename from TiDAL.md rename to docs/TiDAL.md diff --git a/TiLDA_MK3/App_Store_Submissions.md b/docs/TiLDA_MK3/App_Store_Submissions.md similarity index 100% rename from TiLDA_MK3/App_Store_Submissions.md rename to docs/TiLDA_MK3/App_Store_Submissions.md diff --git a/Badge16_Ideas.md b/docs/TiLDA_MK3/Badge16_Ideas.md similarity index 100% rename from Badge16_Ideas.md rename to docs/TiLDA_MK3/Badge16_Ideas.md diff --git a/Badge_Competition_2016.md b/docs/TiLDA_MK3/Badge_Competition_2016.md similarity index 100% rename from Badge_Competition_2016.md rename to docs/TiLDA_MK3/Badge_Competition_2016.md diff --git a/TiLDA_MK3/Firmware_Update.md b/docs/TiLDA_MK3/Firmware_Update.md similarity index 100% rename from TiLDA_MK3/Firmware_Update.md rename to docs/TiLDA_MK3/Firmware_Update.md diff --git a/TiLDA_MK3/Get_Started.md b/docs/TiLDA_MK3/Get_Started.md similarity index 100% rename from TiLDA_MK3/Get_Started.md rename to docs/TiLDA_MK3/Get_Started.md diff --git a/TiLDA_MK3/How_to_fix_NeoPixel.md b/docs/TiLDA_MK3/How_to_fix_NeoPixel.md similarity index 100% rename from TiLDA_MK3/How_to_fix_NeoPixel.md rename to docs/TiLDA_MK3/How_to_fix_NeoPixel.md diff --git a/TiLDA_MK3/Ideas.md b/docs/TiLDA_MK3/Ideas.md similarity index 100% rename from TiLDA_MK3/Ideas.md rename to docs/TiLDA_MK3/Ideas.md diff --git a/TiLDA_MK3/Ideas/hab.md b/docs/TiLDA_MK3/Ideas/hab.md similarity index 100% rename from TiLDA_MK3/Ideas/hab.md rename to docs/TiLDA_MK3/Ideas/hab.md diff --git a/TiLDA_MK3/Introduction_to_badge_hacking.md b/docs/TiLDA_MK3/Introduction_to_badge_hacking.md similarity index 100% rename from TiLDA_MK3/Introduction_to_badge_hacking.md rename to docs/TiLDA_MK3/Introduction_to_badge_hacking.md diff --git a/TiLDA_MK3/NeoPixel.md b/docs/TiLDA_MK3/NeoPixel.md similarity index 100% rename from TiLDA_MK3/NeoPixel.md rename to docs/TiLDA_MK3/NeoPixel.md diff --git a/TiLDA_MK3/Run_Code.md b/docs/TiLDA_MK3/Run_Code.md similarity index 100% rename from TiLDA_MK3/Run_Code.md rename to docs/TiLDA_MK3/Run_Code.md diff --git a/TiLDA_MK3_API.md b/docs/TiLDA_MK3/TiLDA_MK3_API.md similarity index 100% rename from TiLDA_MK3_API.md rename to docs/TiLDA_MK3/TiLDA_MK3_API.md diff --git a/TiLDA_MK3/adc.md b/docs/TiLDA_MK3/adc.md similarity index 100% rename from TiLDA_MK3/adc.md rename to docs/TiLDA_MK3/adc.md diff --git a/TiLDA_MK3/apps.md b/docs/TiLDA_MK3/apps.md similarity index 100% rename from TiLDA_MK3/apps.md rename to docs/TiLDA_MK3/apps.md diff --git a/TiLDA_MK3/apps/nmap.md b/docs/TiLDA_MK3/apps/nmap.md similarity index 100% rename from TiLDA_MK3/apps/nmap.md rename to docs/TiLDA_MK3/apps/nmap.md diff --git a/TiLDA_MK3/build.md b/docs/TiLDA_MK3/build.md similarity index 100% rename from TiLDA_MK3/build.md rename to docs/TiLDA_MK3/build.md diff --git a/TiLDA_MK3.md b/docs/TiLDA_MK3/index.md similarity index 99% rename from TiLDA_MK3.md rename to docs/TiLDA_MK3/index.md index 8e2d0fc..c562b67 100644 --- a/TiLDA_MK3.md +++ b/docs/TiLDA_MK3/index.md @@ -237,4 +237,4 @@ NOTE: The WS2812B is actually on pin PB13, not X2 as shown below! pinout-1.png \ No newline at end of file +alt="pinout2-1.png" /> diff --git a/TiLDA_MK3/memory_problems.md b/docs/TiLDA_MK3/memory_problems.md similarity index 100% rename from TiLDA_MK3/memory_problems.md rename to docs/TiLDA_MK3/memory_problems.md diff --git a/TiLDA_MK3/modtilda.md b/docs/TiLDA_MK3/modtilda.md similarity index 100% rename from TiLDA_MK3/modtilda.md rename to docs/TiLDA_MK3/modtilda.md diff --git a/TiLDA_MK3/reset.md b/docs/TiLDA_MK3/reset.md similarity index 100% rename from TiLDA_MK3/reset.md rename to docs/TiLDA_MK3/reset.md diff --git a/TiLDA_MK3/rtc.md b/docs/TiLDA_MK3/rtc.md similarity index 100% rename from TiLDA_MK3/rtc.md rename to docs/TiLDA_MK3/rtc.md diff --git a/TiLDA_MK3/spi.md b/docs/TiLDA_MK3/spi.md similarity index 100% rename from TiLDA_MK3/spi.md rename to docs/TiLDA_MK3/spi.md diff --git a/TiLDA_MK3/subtree.md b/docs/TiLDA_MK3/subtree.md similarity index 100% rename from TiLDA_MK3/subtree.md rename to docs/TiLDA_MK3/subtree.md diff --git a/TiLDA_MK3/timer.md b/docs/TiLDA_MK3/timer.md similarity index 100% rename from TiLDA_MK3/timer.md rename to docs/TiLDA_MK3/timer.md diff --git a/TiLDA_MK3/ugfx.md b/docs/TiLDA_MK3/ugfx.md similarity index 100% rename from TiLDA_MK3/ugfx.md rename to docs/TiLDA_MK3/ugfx.md diff --git a/TiLDA_MK3/wifi.md b/docs/TiLDA_MK3/wifi.md similarity index 100% rename from TiLDA_MK3/wifi.md rename to docs/TiLDA_MK3/wifi.md diff --git a/TiLDA_MK4/Badge_Store_Submissions.md b/docs/TiLDA_MK4/Badge_Store_Submissions.md similarity index 100% rename from TiLDA_MK4/Badge_Store_Submissions.md rename to docs/TiLDA_MK4/Badge_Store_Submissions.md diff --git a/TiLDA_MK4/BuildingFirmware.md b/docs/TiLDA_MK4/BuildingFirmware.md similarity index 100% rename from TiLDA_MK4/BuildingFirmware.md rename to docs/TiLDA_MK4/BuildingFirmware.md diff --git a/TiLDA_MK4/Code_Structure.md b/docs/TiLDA_MK4/Code_Structure.md similarity index 100% rename from TiLDA_MK4/Code_Structure.md rename to docs/TiLDA_MK4/Code_Structure.md diff --git a/TiLDA_MK4/Firmware_Update(1).md b/docs/TiLDA_MK4/Firmware_Update(1).md similarity index 100% rename from TiLDA_MK4/Firmware_Update(1).md rename to docs/TiLDA_MK4/Firmware_Update(1).md diff --git a/TiLDA_MK4/Get_Started(1).md b/docs/TiLDA_MK4/Get_Started(1).md similarity index 100% rename from TiLDA_MK4/Get_Started(1).md rename to docs/TiLDA_MK4/Get_Started(1).md diff --git a/TiLDA_MK4/Neopix.md b/docs/TiLDA_MK4/Neopix.md similarity index 100% rename from TiLDA_MK4/Neopix.md rename to docs/TiLDA_MK4/Neopix.md diff --git a/TiLDA_MK4/Run_Code(1).md b/docs/TiLDA_MK4/Run_Code(1).md similarity index 100% rename from TiLDA_MK4/Run_Code(1).md rename to docs/TiLDA_MK4/Run_Code(1).md diff --git a/TiLDA_MK4.md b/docs/TiLDA_MK4/index.md similarity index 100% rename from TiLDA_MK4.md rename to docs/TiLDA_MK4/index.md diff --git a/TiLDA_MK4/modtilda(1).md b/docs/TiLDA_MK4/modtilda(1).md similarity index 100% rename from TiLDA_MK4/modtilda(1).md rename to docs/TiLDA_MK4/modtilda(1).md diff --git a/TiLDA_MK4/reset(1).md b/docs/TiLDA_MK4/reset(1).md similarity index 100% rename from TiLDA_MK4/reset(1).md rename to docs/TiLDA_MK4/reset(1).md diff --git a/TiLDA_MK4/sensors.md b/docs/TiLDA_MK4/sensors.md similarity index 100% rename from TiLDA_MK4/sensors.md rename to docs/TiLDA_MK4/sensors.md diff --git a/TiLDA_MK4/sim800.md b/docs/TiLDA_MK4/sim800.md similarity index 100% rename from TiLDA_MK4/sim800.md rename to docs/TiLDA_MK4/sim800.md diff --git a/TiLDA_MK4/sim800/Reverse_engineering.md b/docs/TiLDA_MK4/sim800/Reverse_engineering.md similarity index 100% rename from TiLDA_MK4/sim800/Reverse_engineering.md rename to docs/TiLDA_MK4/sim800/Reverse_engineering.md diff --git a/TiLDA_MK4/tilda-tools.md b/docs/TiLDA_MK4/tilda-tools.md similarity index 100% rename from TiLDA_MK4/tilda-tools.md rename to docs/TiLDA_MK4/tilda-tools.md diff --git a/TiLDA_MK4/ugfx(1).md b/docs/TiLDA_MK4/ugfx(1).md similarity index 100% rename from TiLDA_MK4/ugfx(1).md rename to docs/TiLDA_MK4/ugfx(1).md diff --git a/TiLDA_MKe/FreeRTOS.md b/docs/TiLDA_MKe/FreeRTOS.md similarity index 100% rename from TiLDA_MKe/FreeRTOS.md rename to docs/TiLDA_MKe/FreeRTOS.md diff --git a/TiLDA_MKe/Full_Specification.md b/docs/TiLDA_MKe/Full_Specification.md similarity index 100% rename from TiLDA_MKe/Full_Specification.md rename to docs/TiLDA_MKe/Full_Specification.md diff --git a/TiLDA_MKe.md b/docs/TiLDA_MKe/index.md similarity index 91% rename from TiLDA_MKe.md rename to docs/TiLDA_MKe/index.md index aa21b8e..ddced0d 100644 --- a/TiLDA_MKe.md +++ b/docs/TiLDA_MKe/index.md @@ -1,5 +1,5 @@ - ![](Badge_Front.png "Badge_Front.png") +![](/images/IMG_0474.jpg "IMG_0474.jpg") +![](/images/Badge_Front.png "Badge_Front.png") [Why MKe?](http://en.wikipedia.org/wiki/E_(mathematical_constant)) @@ -26,8 +26,6 @@ supplier problem meant two issues arose with the badge during EMF: power. "Red" and "Black" are written next to the connector - please make sure to plug it in correctly. - - - **Be careful not to short the battery connector wires!** The new battery connector slightly exposes the wires when the battery is plugged in. If a metal object shorts the two wires, it can result in @@ -63,7 +61,7 @@ do! Most of the interesting things are on the back of the badge. They're clearly marked in white. [This diagram of the -back](https://wiki.emfcamp.org/w/images/b/bd/Badge_Back.png) should +back](images/Badge_Back.png) should allow you to locate them. Some of the following require extra parts to be added to your badge. @@ -87,8 +85,7 @@ be added to your badge. - 2x RGB LEDs on the front Some features are not mentioned here, or optional extras. They can be -found in the TiLDA_MKe/Full_Specification +found in the (Full_Specification)[Full Specification] # The Software @@ -98,10 +95,7 @@ We made sure that the badge has a few features to play with once the event is over. More will be added over time as attendees submit changes to us. -
- -
Badge_Back.png
-
+![](/images/Badge_Back.png "Badge Back") - Torch mode - Press the light button next to the screen. It will only light up fully if it's hung upside down to avoid blinding @@ -230,9 +224,7 @@ the RX and TX LEDs ## Programming the badge in FreeRTOS -See -this page for information on howto program your badge using FreeRTOS +See [this page](FreeRTOS) for information on howto program your badge using FreeRTOS ## Contribute @@ -249,8 +241,9 @@ review and merge the good ones so others can use them. ## Making the badge Arduino shield compatible - To make the badge Arduino shield compatible +![](Sheild_Headers.JPG "Shield Header Pinout") + +To make the badge Arduino shield compatible you'll need to solder simple strips of header pins onto the back of the badge. You need the following headers @@ -278,6 +271,3 @@ All the source code and designs are on openly available on Github: If you want to help, point your IRC client to \#emfcamp-badge on [Libera IRC](https://libera.chat/). - -Category: Badges \ No newline at end of file diff --git a/UHB-IF/Issued_IDs.md b/docs/UHB-IF/Issued_IDs.md similarity index 100% rename from UHB-IF/Issued_IDs.md rename to docs/UHB-IF/Issued_IDs.md diff --git a/UHB-IF/Uncontrolled_IDs.md b/docs/UHB-IF/Uncontrolled_IDs.md similarity index 100% rename from UHB-IF/Uncontrolled_IDs.md rename to docs/UHB-IF/Uncontrolled_IDs.md diff --git a/UHB-IF.md b/docs/UHB-IF/index.md similarity index 100% rename from UHB-IF.md rename to docs/UHB-IF/index.md diff --git a/800px-SiNE_Front_Angle.jpeg b/docs/images/800px-SiNE_Front_Angle.jpeg similarity index 100% rename from 800px-SiNE_Front_Angle.jpeg rename to docs/images/800px-SiNE_Front_Angle.jpeg diff --git a/Badge_Back.png b/docs/images/Badge_Back.png similarity index 100% rename from Badge_Back.png rename to docs/images/Badge_Back.png diff --git a/Badge_Front.png b/docs/images/Badge_Front.png similarity index 100% rename from Badge_Front.png rename to docs/images/Badge_Front.png diff --git a/EMF_Badge_Antenna_Mod.jpg b/docs/images/EMF_Badge_Antenna_Mod.jpg similarity index 100% rename from EMF_Badge_Antenna_Mod.jpg rename to docs/images/EMF_Badge_Antenna_Mod.jpg diff --git a/GSM_Antenna.jpg b/docs/images/GSM_Antenna.jpg similarity index 100% rename from GSM_Antenna.jpg rename to docs/images/GSM_Antenna.jpg diff --git a/Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg b/docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg similarity index 100% rename from Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg rename to docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg diff --git a/Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg b/docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg similarity index 100% rename from Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg rename to docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg diff --git a/Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg b/docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg similarity index 100% rename from Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg rename to docs/images/Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg diff --git a/IMG_0474.jpg b/docs/images/IMG_0474.jpg similarity index 100% rename from IMG_0474.jpg rename to docs/images/IMG_0474.jpg diff --git a/Sensor_graphic_-_with_fixed_transparency-01.png b/docs/images/Sensor_graphic_-_with_fixed_transparency-01.png similarity index 100% rename from Sensor_graphic_-_with_fixed_transparency-01.png rename to docs/images/Sensor_graphic_-_with_fixed_transparency-01.png diff --git a/Sensor_graphic_-_with_fixed_transparency-02.png b/docs/images/Sensor_graphic_-_with_fixed_transparency-02.png similarity index 100% rename from Sensor_graphic_-_with_fixed_transparency-02.png rename to docs/images/Sensor_graphic_-_with_fixed_transparency-02.png diff --git a/Sheild_Headers.jpeg b/docs/images/Sheild_Headers.jpeg similarity index 100% rename from Sheild_Headers.jpeg rename to docs/images/Sheild_Headers.jpeg diff --git a/TiLDA_MK3_front.jpg b/docs/images/TiLDA_MK3_front.jpg similarity index 100% rename from TiLDA_MK3_front.jpg rename to docs/images/TiLDA_MK3_front.jpg diff --git a/TiLDA_Mk4_Front_with_sponsors.png b/docs/images/TiLDA_Mk4_Front_with_sponsors.png similarity index 100% rename from TiLDA_Mk4_Front_with_sponsors.png rename to docs/images/TiLDA_Mk4_Front_with_sponsors.png diff --git a/Tilda_MKe.jpg b/docs/images/Tilda_MKe.jpg similarity index 100% rename from Tilda_MKe.jpg rename to docs/images/Tilda_MKe.jpg diff --git a/Tumblr_inline_n9znh3W5tC1rpuop0.jpg b/docs/images/Tumblr_inline_n9znh3W5tC1rpuop0.jpg similarity index 100% rename from Tumblr_inline_n9znh3W5tC1rpuop0.jpg rename to docs/images/Tumblr_inline_n9znh3W5tC1rpuop0.jpg diff --git a/pinout-1.png b/docs/images/pinout-1.png similarity index 100% rename from pinout-1.png rename to docs/images/pinout-1.png diff --git a/pinout2-1.png b/docs/images/pinout2-1.png similarity index 100% rename from pinout2-1.png rename to docs/images/pinout2-1.png diff --git a/index.md b/docs/index.md similarity index 97% rename from index.md rename to docs/index.md index 8f4f322..08b2806 100644 --- a/index.md +++ b/docs/index.md @@ -9,10 +9,9 @@ anyone can play with it. - matrix: '''[\#badge:emfcamp.org](https://matrix.to/#/#badge:emfcamp.org) -## EMF2024 - Tildagon +## EMF2024+ - Tildagon -**[Tildagon preliminary -documentation](https://tildagon.badge.emfcamp.org/)** +**[Tildagon documentation](https://tildagon.badge.emfcamp.org/)** Announcement blog post: **[Tildagon: The EMF 2024+ badge](https://blog.emfcamp.org/2024/03/18/tildagon/)** diff --git a/main.py b/main.py new file mode 100644 index 0000000..1d2fbf3 --- /dev/null +++ b/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from badge-website!") + + +if __name__ == "__main__": + main() diff --git a/mediawiki_export/EMF+Badge-20250904133600.xml b/mediawiki_export/EMF+Badge-20250904133600.xml deleted file mode 100644 index 17c75f9..0000000 --- a/mediawiki_export/EMF+Badge-20250904133600.xml +++ /dev/null @@ -1,4919 +0,0 @@ - - - EMF Badge - badgewiki - https://badge.emfcamp.org/wiki/Main_Page - MediaWiki 1.39.6 - first-letter - - Media - Special - - Talk - User - User talk - EMF Badge - EMF Badge talk - File - File talk - MediaWiki - MediaWiki talk - Template - Template talk - Help - Help talk - Category - Category talk - - - - Badge16 Ideas - 0 - 10 - - 28 - 27 - 2015-05-21T16:44:59Z - - Mbrejza - 5 - - - 28 - wikitext - text/x-wiki - -== Software == -*Interpreter for high level functionality -*microPython / eLUA - run 'out of the box' on several microcontrollers. Would just require HAL c code for access to peripherals -**Would allow users to run their own code on the badge without any additional software on their PCs. micropython appears as mass storage or via a terminal on USB -*have SD card support for additional user storage - -== User Interface (Screen Options) == -*'low res' black & white LCD (as 2014) -**can be seen during the day without a backlight -**backlight needed at night (~10mA) -**good outside contrast -*'high res' colour TFT LCD -**higher resolution and colour adds to experience -**backlight needed all the time (can be dimmed in low light) -**contrast is poor in daylight -**cost about the same as the mono LCD -**'transflective' modules with improved daylight contrast available, but likely increased cost - - -== Wireless Network == -*Downloading camp info -*Can be used to obtain badge location based on RSSI -*send messages to friends -*ask for friends location -*sensor network -**combine with location to map temperatures and so on over the weekend -*potential parts - MRF89XA (3mA rx current, 868MHz, 10mW) - - -== Other peripherals == -*IR for sharing between badges -**can share python/LUA scripts, contact details -**used to 'friend people' to share messages via the radio -*accelerometer to go into low power mode when put down -**eg MMA8652 (40p) -*buzzer/speaker for notifications (and general use) - - -== Power supply == -*ideally would last the weekend (60 hours) -*single AA -**standard alkaline - 2.5Whr (~15mA average at 3.3V) -**lithium AA - 4.5Whr (~25mA average at 3.3V) -*lipo -**2014 lipo ~4Whr -**requires charging circuitry -**ideally wants a hard back to prevent damage -**increased cost - -== Hackability == -*conductive thread pads next to lanyard -**supply little bags of LEDs and thread for say £2 -*extra GPIO broken out -**ardiuno footprint? -*python/LUA would allow for beginners to hack the badge - sxgkgv1mn40at883m89g1dxwl49hlg1 - - - - Badge Competition 2016 - 0 - 46 - - 248 - 246 - 2016-10-02T16:24:12Z - - Jonty - 45 - - 248 - wikitext - text/x-wiki - We're running a competition for the best use of the TiLDA Mk3 badge from EMF 2016. We'll award a prize in two categories: software and hardware. - -The prize in both categories will be '''two tickets to EMF 2018''' (plus the 2017 one-day event if it happens), with the runners up getting another TiLDA Mk3 badge. - -==Entering== - -All apps [http://api.badge.emfcamp.org/ submitted to the app library] will be considered for the competition. If your entry can't be uploaded to the library, drop us an email at badge@emfcamp.org. - -Entries will close on December 31st, 2016. - nbfd6tdr7w8gjfepqh9xktkq73hq6av - - - - Main Page - 0 - 1 - - 481 - 480 - 2024-03-18T20:45:46Z - - Sknebel - 64 - - float-right TOC instead - 481 - wikitext - text/x-wiki - The aim of the EMF badge is to give people interesting hardware they've probably not experimented with before while being simple enough that anyone can play with it. -<div style="float:right">__TOC__</div> -==Contacting the badge team== - -* email: '''badge@emfcamp.org''' -* irc: '''irc.libera.chat #emfcamp-badge''' -* matrix: '''[https://matrix.to/#/#badge:emfcamp.org #badge:emfcamp.org] - -==EMF2024 - Tildagon== -'''[https://tildagon.badge.emfcamp.org/ Tildagon preliminary documentation]''' - -Announcement blog post: '''[https://blog.emfcamp.org/2024/03/18/tildagon/ Tildagon: The EMF 2024+ badge]''' - -<blockquote>Introducing the Tildagon: A reusable badge with modular components upgraded at each event, and hexpansion slots to fill with your own creations.</blockquote> - - - - -==EMF2022 - TiDAL== - -'''[[TiDAL|TiDAL documentation main page]].''' - -'''[https://2022.badge.emfcamp.org App store hatchery].''' - -==EMF2018 - TiLDA Mkδ== -[[File:TiLDA_Mk4_Front_with_sponsors.png|right|thumb|TiLDA Mk𝛿|link=TiLDA_MK4]] - -'''[[TiLDA_MK4|TiLDA Mkδ main page]].''' - -2018 badge announcement on our blog<br/> - -http://blog.emfcamp.org/post/177423823788/tilda-mk4-the-emf-2018-badge -<div style="clear: both"></div> - -==EMF2016 - TiLDA Mkπ== -[[File:TiLDA_MK3_front.jpg|right|thumb|TiLDA Mkπ|link=TiLDA_MK3]] - -[[TiLDA_MK3]] main page. - -2016 badge announcement on our blog<br/> - -http://blog.emfcamp.org/post/144514906298/tilda-mkπ-the-hackable-conference-badge-that - -Update, we have sponsors, the badge is saved! - -http://blog.emfcamp.org/post/145667126793/the-emf-tilda-badge-is-saved -<div style="clear: both"></div> -==EMF2014 - TiLDA MKe== -[[File:Tumblr_inline_n9znh3W5tC1rpuop0.jpg|right|thumb|TiLDA MKe]] - -The [[TiLDA MKe|TiLDA MKe project]] is code named "ElectroMagnetic Boogaloo" - -The MKe is an entirely new design, based on the Arduino Due. It brings an LCD display, Accelerometer and Gyro, along with a long-range wireless transceiver. The original specification was to give people live schedule updates and camp notifications, but the hardware was capable of much more. - -Please Note: There are a couple of minor hardware and some firmware issues with the MKe that might be effecting your badge. If you've let the magic smoke out of your charge controller or have tried to re-flash and ended up with nothing but a couple of dimly glowing lights then DO NOT DESPAIR -It's recoverable and fixes, documentation and lots of firmware are still being produced :) -<div style="clear: both"></div> - -==EMW2013 - SiNE== -[[File:800px-SiNE_Front_Angle.JPG|thumb|300px]] -[[SiNE|SiNE: Investigating the Neighbourhood of EMW]] - -Each attendee of Electromagnetic Wave received a SiNE badge, allowing them to take part in a treasure hunt based around the boat. By solving the clues, attendees were directed to an object or location either on or near the Stubnitz. The clue letter was also the first letter of the answer - large matching letters fitted with IR code transmitters were stored at each location. Holding your badge in front of the letter lit the corresponding light on a badge, allowing the user to collect them all! - -<div style="clear: both"></div> - -==EMF2012 - TiLDA MK1== -[[File:Emf2012_badge_pcb.png|thumb|300px]]<br/> -[http://wiki-archive.emfcamp.org/2012/articles/b/a/d/Badge.html TiLDA]<br/> -The first EMF camp badge, base around the Arduino Leonard, with on board IR, NRF24 Radio and RGB LED's.<br/> -[http://blog.emfcamp.org/post/28558155390/revealing-tilda-our-camp-badge Revealing TiLDA, our camp badge!] - -<div style="clear: both"></div> - -==[[Team:Badge|Badge Team]]== - -The badge team is being headed by -*[[User:Dpslwk|'RepRap' Matt]] from Nottinghack -*[[User:thinkl33t|Bob]] from Hackspace Manchester - 110a929wtbbpn1x9h382i2jt5n4mtjb - - - - SiNE - 0 - 2 - - 266 - 265 - 2017-05-09T15:55:01Z - - Jonty - 45 - - 266 - wikitext - text/x-wiki - [[File:800px-SiNE_Front_Angle.JPG|thumb|300px]] -==About SiNE== -SiNE: Investigating the Neighbourhood of EMW<br /> -Each attendee of Electromagnetic Wave receives a SiNE badge which has two purposes; firstly it allows you to take part in a treasure hunt based around the boat. By solving the clues you will be directed to an object or location either on or near the Stubnitz. The clue letter is also the first letter of the answer - when you arrive at the correct location you will find a large matching letter. Hold your badge in front of the letter, and the corresponding light on your badge will illuminate. The first person to solve all the clues and bring their fully illuminated badge to the ticket desk wins two tickets to Electromagnetic Field 2014. Anyone else solving the puzzle will be allowed to choose from a selection of prizes for as long as they last! - -The second purpose of the badge is as a locator beacon - as people walk around the boat they will create a trail of the places they visit and the talks they attend. We hope to use this information to better schedule our future events. The data will be made available publicly after the event, and we'll provide a way of finding their badge identifier for those who want to get their own trail. - -===Scavenger hunt=== -As you locate the beacons hidden around EMWave more of your LED's will light up. To save power the LED do not stay on all the time and the beacons you have seen are flash in groups every few seconds.<br /> -The beacons you have seen is store in the EEPROM and so the data is preserved even if you remove the power -====Clue List==== -Now EMWave has past here is the clue list: (Will add answers soon --[[User:Dpslwk|Dpslwk]] ([[User talk:Dpslwk|talk]]) 14:21, 6 May 2013 (UTC)) -*A: I can't believe it's not butter! -*B: Bond would be comfortable here and he has a licence. -*C: One of your EMW badge designers. -*D: One of your EMW badge designers. -*E: Powered by Orange. -*F: ____ and aft. -*G: False patch of nature. -*H: All _____ on deck! -*I: Initial illumination, informing incomers. -*J: Java's main export. -*K: A nautical speed, mooring the Stubnitz. -*L: Budding safecrackers. -*M: An essential orienteering tool. -*N: A German Venus? Not exactly Botticelli! -*O: Fun times in the Emergency Room! -*P: A most unusual Landrover. -*Q: Encoded in a massive square. -*R: A lifesaver in Germany. -*S: Quite possibly the most unusual holiday home. -*T: One of your EMW badge designers. - - -===Locator ID=== -[[File:800px-SiNE_Front_Buttons.jpeg|thumb|300px]] -Each badge is programmed with a unique ID, that is transmitted about 5 times a second. There will be Raspberry Pi's doted around the ship, collecting data.<br /> -EMF will not know your badge ID, as there are handed out at random. <br /> -A badge's ID is shown on the LED using binary encoding. -This is done at power up, or by pressing and holding the "ID" button<br /> - -If you '''do not''' wish to have your badge trasnmitting an ID you can clear it by holding the "Erase" button for about 5 seconds. - -The badge ID is 9 bit's long, these are displayed across the A-I LED's, a lit LED is 1 and unlit is 0, LSB first.<br /> -Example if LED's A D E and H are lit then we have 010011001 in binary or 0x099 in HEX or 153 in decimal. - -Unfortunately due to a lack of time the Raspberry Pi's were never setup, as so no data was collected. - -<div style="clear: both"></div> - -==Sponsors== -[[File:800px-SiNE_Back_Angle.JPG|thumb|300px]] -SiNE was only possible thanks to our sponsors: -* [http://www.twilio.com Twilio] A Cloud communications company sponsored the parts need to make badges. -* [http://ciseco.co.uk Ciseco] A Nottingham based electronics company that make low power wireless radios, donated the time to build the badges on there SMT assemble line. -<div style="clear: both"></div> - -===DevBoards=== -[[File:DevBoards.JPG|thumb|300px]] -Before designing the final SiNE badge we built three development boards, not bothered about the looks, they were built to test the hardware and wiring between the parts. <br /> -Once it was confirmed that the parts worked together they were passed onto the software developer to start work on the code need for the scavenger hunt and location tracking. <br /> -Using these development boards meant the software was ready to go around the same time as the final badges were produced. - -<div style="clear: both"></div> -==Badge Hacking== -[[File:800px-SiNE_Schematic.png|thumb|300px]] -We actively encourage users to hack there badge better and hope the information provided below will help - -===Flashing and Fuses=== -We use avrdude and an ISP programer to flash the ATTiny44A -Example command lines can be found in the Makefile in the SiNE-Firmware github - -avrdude part flag (-p) is t44 - -Fuses: -* Low: 0xC2 -* High 0xD7 -* Extended: 0xFF - -===Components=== -The following parts were used: (data-sheet links to come) -* ATTiny44A - MCU running all the code -* 74HCT164AD - Shift register connecting the matrix of LED's -* LED's - 20 0805 LED's for each of the hidden locations -* IR Receiver - listening for the unique ID of each of the hidden beacons -* IR Sender - sending out the badges ID for Location tracking -* 2032 Coin Cell - Power for the day and possible more -* ISP header - Used for programming of the ATTiny44A - -===Resources=== -* [https://github.com/EMF-TiLDA/SiNE-PCB PCB] -* [https://github.com/EMF-TiLDA/SiNE-Firmware Firmware] - -[[Category:Badges]] - 4ptlx3fqx2y56edbagvit38ht5m6rop - - - - TiDAL - 0 - 82 - - 478 - 475 - 2022-06-19T18:39:47Z - - 0x47df - 83 - - link hardware repository - 478 - wikitext - text/x-wiki - To do an OTA Update and get the latest firmware make sure your battery is charged! - -You may have to get very close to an access point (within a couple of metres) for the WiFi to work. Sorry! The more busy an access point is, the more difficulty the TiDAL badge will have communicating. - -* Documentation https://github.com/emfcamp/tidal-docs -* Firmware Repository https://github.com/emfcamp/TiDAL-Firmware -* Hardware Repository https://github.com/emfcamp/TiDAL-Hardware -* Flyer https://usercontent.irccloud-cdn.com/file/tRv4Lyv4/badge+flyer.pdf - maf4t8295khiwwuowa818u6qjpp2l9d - - - - TiLDA MK3 - 0 - 12 - - 464 - 284 - 2021-05-26T08:16:24Z - - Thinkl33t - 2 - - 464 - wikitext - text/x-wiki - [[File:TiLDA_MK3_front.jpg|right|500px|TiLDA Mkπ]] - -== Using your badge == - -<div style="background-color: #FFFFDD; border: 1px solid #808000; padding: 5px;"><strong>If you just got your badge and it doesn't do anything</strong>, don't despair, quite a few of them need to be [[TiLDA_MK3/reset|factory reset]] before showing the loading screen. Press and hold <code>MENU</code> while quickly pressing the reset button at the back. Keep the <code>MENU</code> button hold for another 2 seconds while the green light on the front is blinking. Release it <i>while</i> the green light <b>and</b> the screen back light is on. If you got it correct the red light should flash.<br>If this doesn't work you can [[TiLDA_MK3/Firmware_Update|update the badge firmware]]. If this doesn't work, please come and join us in #emfcamp-badge on [https://libera.chat/ Libera IRC]</div> - - -<div style="background-color: #DDFFFF; border: 1px solid #808000; padding: 5px;">If you're having problems downloading some apps from the App Library <b>please update your badge via the App Library update option</b>. After a restart it should work much smoother.</div> - -=== Assembly === -With your badge you will receive a booklet explaining how it's done. If you have any problems, please come to the Badge Operation Center and we will help you. - -=== Basic usage === -After you have assembled your badge you can just use the tiny switch at the bottom of the screen to turn your badge on. Alternatively you can use any USB power source. If you turn your badge on for the first time (or if for some reason it has reset itself) you will get some on-screen information while we try to download the newest set of software. - -If at any point you want to restart your badge you can just press the reset button at the back. - -==== Changing your name ==== - -# Press 'Menu' -# Select the 'Change Name' app and press 'A' -# Use the joystick and 'A' key to enter your name -# Press 'Menu' to save your name and reset the badge - your name should now be displayed! - -==== Installing new apps ==== - -# Press 'Menu' -# Select the 'App Library' app and press 'A' -# Select "Browse App Store" -# Select a category and then an app. Wait until you see the description and press "A" to save it. -# Press B a few times (or alternatively MENU) to restart your badge -# On the home screen you can now press MENU and select "View all" to find your newly installed app. If you want to pin it to the quick launcher screen select your app and press MENU. If you just want to start it press A instead. - -=== WiFi === -Your TiLDA Badge has built-in wifi support. It should all just work if you're at the campsite, but if you're on your own network you might have to tell the badge about it. For more information please have a look here: [[TiLDA MK3/wifi|WiFi]] - -<strong>A word of warning</strong>: During EMF the badge will use "emf-insecure". This is, as the name implies, not the most secure way of transmitting data. On top of that there are some problems with HTTPS and SSL, so we're not using it for with the default apps (we're working on it!). Please <span style="color:red">don't send anything private or important to or from the badge via wifi</span>. - -=== Charging === -The badge charges via a microUSB socket, and takes about 2-3 hours for a full charge. The red charge LED next to the USB connector will extinguish when charging is complete - -=== Nothing works! Help! === - -Don't worry, you can always "factory reset" your badge. Please follow these instructions: [[TiLDA_MK3/reset|Resetting]] - -If everything else absolutely fails, you can try following these instructions (advanced): [[TiLDA_MK3/Firmware_Update]] - -== Hacking your badge == - - -'''[[TiLDA_MK3/Introduction_to_badge_hacking|Badge Hacking Workshop Documentation]]''' - - -One of the main goals of TiLDA is to make hacking it as easy as possible. All you need to do so is a computer with USB and your badge. - -* '''[[TiLDA MK3/Get Started|Step-by-step: How to get started]]''' -* '''[[TiLDA MK3/Run Code|3 Ways to run code on your TiLDA]]''' -* [[TiLDA MK3/App Store Submissions|App Store Submissions]] - -The badge itself runs code written in the computer language [https://en.wikipedia.org/wiki/Python_(programming_language) Python] which is run by a bit of software called [https://micropython.org/ Micropython]. - -For more information about the functions available please have a look at the [[#Badge API|Badge API]] section of this page. - -If you're already familiar with all this you can jump right into the topic of Apps. Apps can be shared via the EMF App Library or by copying files of and on via USB. If you want to know more about how this works go to [[TiLDA MK3/apps]] - -In case you're more interested in what makes the hardware tick and your confident with C++ and microprocessors then you can work directly with the micropython code that runs TiLDA: [[TiLDA MK3/build|How to build the firmware from scratch]] - -All code used is hosted on Github. Contributions and PR are very welcome! -* https://github.com/emfcamp/micropython -* https://github.com/emfcamp/Mk3-Firmware -* https://github.com/emfcamp/Mk3-Server - -=== Some ideas === - -[[TiLDA MK3/Ideas|Please share what you've done (or want to do) with others!]] - -[https://github.com/emfcamp/Mk3-Hardware/blob/master/case-final.dxf Laser cut case files] - -The files used in the '''Fab Lab Truck''' for lasercutting are available here: http://www.thingiverse.com/thing:1707973 - -== Badge API == - -=== Build-in === -* [http://docs.micropython.org/en/latest/pyboard/ documentation] - General Micropython libarary -* [[TiLDA MK3/ugfx|uGFX]] - The TiLDA LCD colour screen -* [[TiLDA MK3/documentation/cc3100|CC3100]] - The wifi chip -* [[TiLDA MK3/rtc|RTC]] (real time clock) -* [[TiLDA MK3/adc|ADC]] (analogue reading) -* [[TiLDA MK3/timer|Timer]] -* Microcontroller peripherals [https://docs.micropython.org/en/latest/pyboard/library/pyb.html] (Timers, PWM, serial, [[TiLDA MK3/spi|SPI]] etc) - -=== TiLDA Libraries === -On top of the build-in modules above we have also created a bunch of helpful libraries written in python. If you go through the bootstrap process or use the App Library you should always have a full set of those on your badge. If for some reason this isn't the case you can download our repository from https://github.com/emfcamp/Mk3-Firmware and copy the <code>lib</code> folder onto your badge. - -TBD, for now please have a look at the libraries themselves: https://github.com/emfcamp/Mk3-Firmware/tree/master/lib - -* [[TiLDA MK3/lib/buttons|buttons]] -* database -* dialogs -* filesystem -* http_client -* imu -* wifi -* NTP Example: https://gist.github.com/drrk/4a17c4394f93d0f9123560af056f6f30 -* On board LED "[[TiLDA MK3/NeoPixel|NeoPixel]]" example: https://github.com/mayhem/tilda-mk3-led-demo - -Full hardware files are on GitHub [https://github.com/emfcamp/Mk3-Hardware] - -(feel free to add additional ideas, and create links new wiki pages to on-going projects, perhaps someone will want to contribute) - -== Badge hardware == -TiLDA comes with a long list of very useful hardware. Some might be obvious, but some are a bit hidden. -* Colour LCD screen 320x240 -* Joystick and A/B/Menu Buttons -* Wifi (cc3100) -* Accelerometer -* Compass -* Buzzer -* Battery -* <s>WS2812B aka "Neo Pixel"</s> on port PB13. [https://badge.emfcamp.org/wiki/TiLDA_MK3/How_to_fix_NeoPixel Sadly defunct] -* MicroSD slot - -Harware files are available on GitHub [https://github.com/emfcamp/Mk3-Hardware]. - -NOTE: The WS2812B is actually on pin PB13, not X2 as shown below! - -[[File:pinout-1.png | 500px]] [[File:pinout2-1.png | 500px]] - odrthxysonfp0cjk6saia6pyslb5bky - - - - TiLDA MK3/ - 0 - 75 - - 400 - 399 - 2018-09-02T09:33:29Z - - Finnn - 52 - - - 400 - wikitext - text/x-wiki - You are looking for the root page; [[TiLDA_MK3]]. - 7xxlx3x37md0dv46ko6w5v3r3s5ncf6 - - - - TiLDA MK3/adc - 0 - 21 - - 255 - 110 - 2017-03-02T00:50:40Z - - Claude - 47 - - fix broken link to micropython adc docs - 255 - wikitext - text/x-wiki - See here [https://docs.micropython.org/en/latest/pyboard/library/pyb.ADC.html] for the main micropython documentation. - -All ADC readings are referenced to the supply rail, which is about 3.3V. To increase the ADC accuracy, the internal voltage reference can be read, and used to offset variations in the supply rail. - -<pre> -adcin = pyb.ADC(channel_to_read).read() -ref_reading = pyb.ADC(0).read() -supply_voltage = 4095/ref_reading*1.21 # or change 1.21 with the calibrated value - see below -adc_voltage = adcin / 4095 * supply_voltage -</pre> - -Note, the factory reads the internal reference with a supply voltage of 3.0V, and stores this reading. This can then be used to get the actual voltage reference. For example -<pre> -import stm -factory_reading = stm.mem16[0x1FFF75AA] -reference_voltage = factory_reading/4095*3 # will be approximately 1.21V -</pre> - -For convenience, the library `onboard' provides the following functions for reading the battery voltage, unregulated voltage, or light level -<pre> -import onboard -onboard.get_battery_voltage() -onboard.get_unreg_voltage() -onboard.get_light() -</pre> - tbryjbcunslkryw54xf5il4q4k269c9 - - - - TiLDA MK3 API - 0 - 17 - - 46 - 45 - 2016-07-13T14:51:58Z - - Marekventur - 10 - - 46 - wikitext - text/x-wiki - === GET api-badge.emf.camp/apps.json === -<pre> -{ - "games": [ - { - user: "someuser" - name: "snake", - description: "Some game with a snake", - files: { - "main.py": "abcdefgh", - "images.bmp": "abcdefg" - } - }, - { - user: "someuser2" - name: "tetris", - description: "Some game with a snake", - files: { - "main.py": "abcdefgh", - "images.bmp": "abcdefg" - } - } - ], - "emf": [...] - ... -} -</pre> - - -=== GET api-badge.emf.camp/someuser/snake.json === -<pre> -{ - user: "someuser" - name: "snake", - description: "Some game with a snake", - files: { - "main.py": "abcdefgh", - "images.bmp": "abcdefg" - } -} -</pre> - l4vuyeu8i04rvc1xjwyesirpmj32qky - - - - TiLDA MK3/apps - 0 - 18 - - 401 - 50 - 2018-09-02T09:35:45Z - - Finnn - 52 - - 401 - wikitext - text/x-wiki - ToDo: How to create, test and publish apps - -This section is defunct, but [[TiLDA_MK3#Hacking_your_badge]] will probably help you. - nr6y2wzgovarwq16nxuoszk4eg7th2w - - - - TiLDA MK3/apps/nmap - 0 - 33 - - 173 - 2016-08-06T12:40:26Z - - Lilafisch - 17 - - create page for tilda nmap app - 173 - wikitext - text/x-wiki - == Description == - -you will see a map with -circles representing the wifi access points you see. -The better the reception for an access point, the larger the diameter of the circle. - -Based on this information, you can estimate where you are! - -github: https://github.com/muccc/tilda-nmap - fs8gwu95w6nfbbtwd5j8340uro8xd3n - - - - TiLDA MK3/App Store Submissions - 0 - 35 - - 183 - 182 - 2016-08-07T09:49:02Z - - Marekventur - 10 - - /* How to submit */ - 183 - wikitext - text/x-wiki - == How to submit == -Zip your folder up, sign up to http://api.badge.emfcamp.org/, create a new app and publish it - -== Common Problems == -Please check these things before publishing your app: -* Your app will end up in "app/username~appname", so please make sure all you paths are using that. Example: <code>open("app/myname~myapp/some.json")</code> -* Please make sure the meta data at the top of the file is ok -* Please make sure to use <code>ugfx.init()</code> and <code>buttons.init()</code>, it makes it easier for me to review - -Besides those, there are currently problems with apps that have too many files (lots of images for example) or use too much memory (big arrays). If it's possible in any way, please try to keep both down. We're working on reducing memory usage. - 4wid5fj1419ef5j1llslkexwtxnx363 - - - - TiLDA MK3/build - 0 - 14 - - 269 - 268 - 2017-08-25T22:30:56Z - - Raj - 23 - - /* USB Permissioning on Linux */ - spelling error - 269 - wikitext - text/x-wiki - == Dependencies == - -You can use either windows or linux, although windows will not have most things installed by default - -=== git, make, python, etc === -I will just assume you have this - -=== arm-none-eabi-gcc === -https://launchpad.net/gcc-arm-embedded/+download -You will have to make the arm-none-eabi-gcc from the bin directory available to your system (add to PATH, symlink or copy) - -On Ubuntu you can follow these instructions: https://launchpad.net/~team-gcc-arm-embedded/+archive/ubuntu/ppa - -On Debian (in Stretch, maybe earlier versions too, also Raspbian Jessie) you can `sudo apt-get install gcc-arm-none-eabi` - -=== pyusb=== -<pre>sudo pip install pyusb</pre> - -== USB Permissioning on Linux == - -On some Linux distributions it may be necessary to add additional udev rules in order to allow the REPL to work: - -copy the following text to /etc/udev/rules.d/49-tilda-mk3.rules - -<pre> -# 0483:df11 - Tilda Mk3 based on Micropython board -ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", ENV{ID_MM_DEVICE_IGNORE}="1" -ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", ENV{MTP_NO_PROBE}="1" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE:="0666" -KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE:="0666" -</pre> - -And then restart the udev service: - -<pre> -sudo udevadm control --reload-rules -</pre> - -== Flashing == - -<pre> -# Clone this repo -git clone --recursive https://github.com/emfcamp/micropython.git - -# Switch to our work branch -cd micropython -git checkout tilda-master - -# Now we can build the firmware and flash it to the badge -# You have to boot the badge into dfu mode by pressing down the center -# joystick button while pressing the reset button to trigger a reboot -make -C stmhal BOARD=STM32L475_EMFBADGE deploy -</pre> - -== What to do when the firmware update.py script fails == - -When attempting an update from linux, some users have hit timeouts during hte mass_erase step. This leaves the badge in an ususable state. - -<pre> -$ python update.py -Hello - Welcome to the automated TiLDA firmware updater -We found your badge. So far, so good... -Traceback (most recent call last): - File "update.py", line 556, in <module> - main() - File "update.py", line 530, in main - mass_erase() - File "update.py", line 114, in mass_erase - "\x41", __TIMEOUT) - File "/usr/local/lib/python2.7/dist-packages/usb/core.py", line 1043, in ctrl_transfer - self.__get_timeout(timeout)) - File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 883, in ctrl_transfer - timeout)) - File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 595, in _check - raise USBError(_strerror(ret), ret, _libusb_errno[ret]) -usb.core.USBError: [Errno 110] Operation timed out -</pre> - -If you have access to a Windows PC, you can download the STMicroelectronics DfuSe USB device firmware updater software http://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-stm32080.html and use the 'Upgrade or Verify Action' part of the GUI to update the firmware instead. - -* Install the STMMicroelectronics util from the link above. -* Download the firmware.dfu file from https://update.badge.emfcamp.org/firmware.dfu and save it off. -* Start up DfuSeDemo.exe, and click the 'Choose' button - select the firmware.dfu file and then hit 'Upgrade' -* Your badge should now be un-bricked - 2h7kzghj6gc1p6732i1algsckak60cf - - - - TiLDA MK3/Firmware Update - 0 - 38 - - 410 - 267 - 2018-09-02T13:36:54Z - - Rabble - 66 - - 410 - wikitext - text/x-wiki - == Update your Tilda Mk3== - -This guide will help you to update your Tilda Mk3 badge. Be careful, following these instructions will delete all files and setting on your badge, so make sure you have copies of everything! - -If you're having trouble following these instructions or updating your badge, [mailto:badge@emfcamp.org please get in touch] and we'll do our best to help. - -== Before you start== - -You need to put your badge into DFU mode. This activates a USB bootloader stored in ROM on the STM32 processor. - -'''To enter DFU mode:''' Switch on the badge. Press the center joystick button while at the same time quickly pushing the reset button on the back of the badge. - -In some cases this seems to require a few attempts. You can also try unplugging the battery, and holding down the center button while plugging in USB. - -==OSX== - -'''Prerequisites needed for Mac OS X''' - -1. XCode (from App Store) - -2. Python & pip -* Homebrew method -*: 1. [http://docs.python-guide.org/en/latest/starting/install/osx/ Install Homebrew and Pip] -*: 2. <code>brew install libusb lsusb</code> -*: 3. <code>pip install libusb1 pyusb</code> -* MacPorts method -*: 1. [http://johnlaudun.org/20150512-installing-and-setting-pip-with-macports/ Install MacPorts and Pip] -*: 2. <code>sudo port install usbutils py-pip</code> -*:: usbutils provides e.g. lsusb, useful for knowing if the badge is connected in DFU mode -*: 3. <code>sudo pip install libusb1 pyusb</code> - -3. Check that you're connected in DFU mode: -: <code>lsusb</code> -: Should output something like: -: <code>Bus 020 Device 002: ID 0483:df11 STMicroelectronics STM Device in DFU Mode</code> - -4. <code>wget https://update.badge.emfcamp.org/update.py</code> - -5. <code>sudo python update.py</code> - -6. To get a shell: <code>screen /dev/tty.usbmodem*</code> - -'''Troubleshooting''' - -If you get the error <code>Error: No backend available</code> then python cannot find the USB library. Please Repeat steps 2 and 3 above, see https://github.com/walac/pyusb/issues/120 for more details. - -== Linux == - -Install prerequisites if required: - -<code>sudo apt install python-usb</code> - -Open a terminal and execute this line: - -<code>curl --silent --show-error --retry 5 https://update.badge.emfcamp.org/update.py | python</code> - -If you get an error saying <code>ImportError: No module named core</code> then the python-usb package in your distribution is too old. On Debian, you should be able to fix it using pip instead: - -<code>sudo apt install python-pip</code> - -<code>sudo pip install --upgrade pyusb</code> - -== Windows == - -'''<span style="color:red">WARNING</span>: There have been reports of badges being bricked when flashed from windows. They can be recovered using the OSX/Linux update procedure. We are looking for alternative ways of updating using Windows.''' - -On a Windows PC, you will need to download the STMicroelectronics DfuSe USB device firmware updater software http://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stsw-stm32080.html and use the 'Upgrade or Verify Action' part of the GUI to update the firmware instead. - -* Install the STMMicroelectronics utility from the link above. -* Download the firmware.dfu file from https://update.badge.emfcamp.org/firmware.dfu and save it. -* With the badge plugged into the computer, hold the centre joystick button and press reset. The badge should now boot into the bootloader, and be detected as a 'STM Device in DFU Mode'. -* Start up DfuSeDemo.exe, and click the 'Choose' button - select the firmware.dfu file and then hit 'Upgrade' -* Your firmware will now be updated. - -== Other Operating systems== - -To update your badge please download the following script and run it via python: [https://update.badge.emfcamp.org/update.py update.py] - -If you know how to flash the badge yourself you can also download the DFU binary directly: [https://update.badge.emfcamp.org/firmware.dfu firmware.dfu] - -== Build your own version== - -If you want to build your own version of the firmware have a look [https://badge.emfcamp.org/wiki/TiLDA_MK3/build here] - 298pwr4o8o0s7nisz5c4fp168ivvda3 - - - - TiLDA MK3/Get Started - 0 - 23 - - 285 - 262 - 2018-07-30T17:32:33Z - - Finnh - 43 - - 285 - wikitext - text/x-wiki - = Get started = - -Hacking your TiLDA badge is easy. We've written it down step by step. - -If something goes wrong, the badge can be [[TiLDA_MK3/reset|reset]] to its out-of-the-box state, so do not be concerned about breaking anything. - -== 1. Connect to your computer == -To get started you need to connect your badge to a computer. You can use any MicroUSB cable - the same type that charges most mobile phones nowadays. It doesn't matter whether the batter is plugged in or not, so don't worry about it. - -== 2. Check your badge is found by your computer == -Upon connecting the badge to a computer, it should appear as a "mass storage device" just like a USB key or an external hard disk. - -'''Important:''' Just like any other USB storage device, if you changed or copied anything on the Badge, please make sure to "eject" or "safely remove" before unplugging your badge or pressing the reset button. Otherwise you might lose all your work :( - -Windows will require a driver file for the serial port, which is stored on the badge's mass storage. [https://micropython.org/resources/Micro-Python-Windows-setup.pdf More information] - -== 3. Connect to your badge == - -=== Windows === -* Please follow the instruction under the "Windows" section on this page: https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html -* Once you've installed the driver and Putty and you've connected to your badge, press Control+C to stop the main badge app, and then you should be greeted by a line saying "Micropython" - -=== OSX === -* Click the magnifying class in the top right of your screen and type <code>Terminal</code> followed by Enter. A white terminal window should appear. -* type <code>screen /dev/tty.usbmodem*</code> (The * is important, so don't let it out) and hit enter -* hit <code>control+c</code>, if an error is displayed -* You should now be greeted by a line saying "Micropython" - -=== Linux === -* Open a terminal and type <code>screen /dev/ttyACM0</code> -* You should now be greeted by a line saying "Micropython" - -=== What to do if this step doesn't work? === -* Press the reset button at the back of your badge and try again -* Have a look at https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html for more information - -== 4. Your first line of Micropython == -* In your terminal (next to the >>>) type <code>print(1 + 1)</code> followed by Enter -* You should see <code>2</code> printed on the screen. Congratulations, you've just written your first line of micropython code! -* You can now close the terminal window (or Putty, if you're on Windows). Note: some serial terminals will not close when the badge is removed or powered off. You should close the serial terminal before plugging the badge back in, otherwise the serial terminal may not reconnect. - -== 5. Download some software you'll need == - -You will be downloading some stuff now. It's probably be best if you create some folder somewhere so you don't end up with files all over your Desktop. - -Note you can copy files across from your computer to the badge, reset the badge and run the files though the menu, however these instructions make things a little easier. - -=== Windows === -* Python: Go to https://www.python.org/downloads/ and download python version 3.x. After the download is finished you can install it. -* Go to https://bootstrap.pypa.io/get-pip.py and save the file into your folder -* Hold shift, right click on the folder on, and click "open command window here" -* Now type <code>python get-pip.py</code> -* After the install was successful please type <code>pip install pyserial pyusb</code> followed by Enter. -* If you do not wish to install python, and would rather copy files across, the command line utility RoboCopy is recommended. For example: <code>Robocopy.exe ./my_app/ d:/apps/my_app</code> - -=== OSX / Linux === - -* Python: Open a terminal and type <code>python --version</code>. If you get a version number you're good to go, otherwise go to https://www.python.org/downloads/ and download Python version 3.x. After the download is finished you can install it. -* Go to https://bootstrap.pypa.io/get-pip.py and save the file into your folder -* Use a terminal to go to the folder you created ([http://www.macworld.com/article/2042378/master-the-command-line-navigating-files-and-folders.html this is how you do it]) and type <code>python get-pip.py</code> -* Now type <code>python get-pip.py</code> -* After the install was successful please type <code>pip install pyserial pyusb</code> followed by Enter - -=== Problems === -* If you have problems install python, please use google, there are lots of good explanations out there -* For information about how to install <code>pip</code> have a look here: https://pip.pypa.io/en/stable/installing/ - -== 6. (Optional) Update your badge's micropython == -'You can skip this step', but since TiLDA is still a work in progress, it's best to update regularly. So why not do it now? It's easy, just follow the instructions here: [[TiLDA_MK3/Firmware_Update]] - -== 5. Run a whole file of code == -While you can do most things via the terminal like you just did, it's a bit easier to work on a file that you can edit. So let's do that. -* Go to https://raw.githubusercontent.com/emfcamp/micropython/tilda-master/tools/pyboard.py and use your browser to save it as "pyboard.py" into your newly created folder -* Open a text editor. On Windows you can search for <code>Notepad</code>, on OSX there's one called <code>textedit</code> and if you're on Linux you can probably find one by searching for "edit". -* Copy the following and save it as <code>test.py</code> in your folder: -<source lang="python"> -print(1 + 2) -</source> -* Open a terminal, navigate to the right folder (see step 5 for more info) -** Windows: <code>python pyboard.py test.py --device=COM4</code> Replace COM4 with whatever port your badge installed as. -** OSX: type <code>python pyboard.py test.py --device=/dev/tty.usbmodem*</code> -** Linux: type <code>python pyboard.py test.py --device=/dev/ttyACM*</code> -* You should now see the your terminal showing <code>3</code>. Your getting good at this! - -'''Hint''': If you don't want the home app to start every time you can create an empty <code>main.py</code> file in the USB folder. This will stop the boot from loading the home screen and allow you do run code on your badge undisturbed. But remember to "safely eject" the badge after writing the file and to remove it again when you want the normal behaviour back - -== 7. Blink == -So far all we've seen is the badge doing some maths and sending the result back via usb. Let's start with one of the simplest hardware device on the badge, a LED (which means "Light emitting diode") -- We want to make it blink. - -Create a file called <code>blink.py</code> and copy this bit of code into it: - -<source lang="python"> -import pyb -led = pyb.LED(1) -led.on() -pyb.delay(500) -led.off() -pyb.delay(500) -led.on() -pyb.delay(500) -led.off() -pyb.delay(500) -led.on() -</source> - -Save it and use a terminal to execute it (See Step 5 - but make sure to replace the filename in the command). Have a look at your badge, you should see the tiny LED labeled "A" (It's right between the B button and the screen) flash twice before and then staying on. - -Now, let's see what the code actually does. - -<source lang="python"> -import pyb -</source> -This line tells your badge to import the "pyb" library. It allows you to do various hardware related things with your badge (the full list is [http://docs.micropython.org/en/latest/pyboard/library/pyb.html here]). This is something very important in python, you always need to import libraries before you can use them. - -<source lang="python"> -led = pyb.LED(1) -</source> -This line uses the pyb module we've just imported and creates a LED object. The "<code>1</code>" means we're using the first LED on the badge. Change it to "<code>2</code>", save it and run pyboard.py again - Now the LED B should flash in green. - -The <code>led</code> bit before the <code>=</code> means that we're not only creating an LED object, but we're also storing it for later use. - -<source lang="python"> -led.on() -</source> -Here we're using the reference to the LED object we've just created and calling the <code>.on()</code> function on it. Most python objects have multiple functions you can use. In this case you can look the them up here: http://docs.micropython.org/en/latest/pyboard/library/pyb.LED.html?highlight=led - -<source lang="python"> -pyb.delay(500) -</source> -This line uses the <code>pyb.delay()</code> function to pause the execution of our program for a while. The <code>500</code> is a number in milliseconds and the code is stopping for half a second. We need this delay to give your eyes some time to see that the LED has turned on. Try playing with different numbers or leaving the line out altogether to get a feeling for it. - -== 8. Blink forever == -Since our original <code>blink.py</code> script is only blinking twice it might be easy to miss. Let's fix this by blinking a bit longer: - -<source lang="python"> -import pyb -led = pyb.LED(1) -while True: - led.toggle() - pyb.delay(500) -</source> - -Be careful to make sure you're copying the spaces in front of the last two lines as well, they're very important in Python! If you want to type them you have to use the <code>Tab</code> key on your keyboard - It's normally on the left of your keyboard, two keys above the <code>Shift</code> key. - -Save this code and run it via <code>pyboard.py</code> again. You should now see the red LED blinking forever. So what's happening here? - -<source lang="python"> -while True: - led.toggle() - pyb.delay(500) -</source> -This is called a "while loop" in Python. It means that a certain bit of code (the one indented by the Tab at the beginning of the line) will be repeated over and over again until a certain condition is not fulfilled anymore. In this case the condition is <code>True</code> which is the Python-way of saying "this is always correct". Therefore the loop will repeat forever. - -<code>led.toggle()</code> is similar to <code>led.on()</code> and <code>led.off()</code>, but instead of always turning the LED on or off it switches between the states. Very useful in our case! - -This kind of "infinite loop" is quite useful for a lot of badge code, but often you also want to have some way of leaving the loop. Try this instead: -<source lang="python"> -import pyb -import buttons -buttons.init() -led = pyb.LED(1) -while not buttons.is_pressed("BTN_MENU"): - led.toggle() - pyb.delay(500) -</source> - -There are a few new things here: First we have imported a new library called <code>buttons</code>. This library helps you with all the buttons on the badge. If you want to use buttons in your script you also have to call <code>buttons.init()</code>, so that's what we're doing in line 3. - -We have also changed the <code>while</code> loop with a new statement <code>not buttons.is_pressed("BTN_MENU")</code>. Like I said above, <code>while</code> loops will go on forever while its condition is fulfilled. We have now changed the condition to be "while the MENU button is not pressed". - -Try running the code. You will again get the same blinking LED, but this time you should be able to stop it by pressing the MENU button. - -== 8. Hello Screen == - -Ok, now let's try to write something on the screen. TiLDA comes with a colour screen and we can use a library called UGFX to draw on it. - -Create a <code>main.py</code> file and put this in there: -<source lang="python"> -import ugfx -import buttons -import pyb - -ugfx.init() -buttons.init() -ugfx.clear(ugfx.YELLOW) - -ugfx.text(5, 5, "Hello World", ugfx.RED) -ugfx.fill_circle(100, 100, 30, ugfx.GREEN) -ugfx.fill_circle(200, 100, 30, ugfx.GREEN) -ugfx.area(80, 150, 140, 20, ugfx.GREEN) -ugfx.area(120, 170, 60, 20, ugfx.GREEN) -</source> - -If you run this file you should see a the screen turn yellow with some text and a (very simple) smiley. - -If you use the screen you have to make sure you're using <code>ugfx.init()</code>, otherwise nothing will work. <code>ugfx.clear()</code> is used to clear the screen (in this case with a special colour) and the next 5 lines are drawing some text and a few basic shapes. - -<code>ugfx.text(x, y, text, color)</code> Prints some text at position (x, y) in a given colour. x and y are coordinates on the screen. x=0 and y=0 means the top-left of the screen and x=320 y=240 is the bottom right corner. Try changing the two numbers and see how the text moves around on the screen. - -<code>ugfx.fill_circle(x, y, radius, color)</code> draws a circle on the screen. - -<code>ugfx.area(x, y, width, height, color)</code> draws a rectangle on the screen. - -There are more basic drawing operations. You can find a list of them here: [[TiLDA MK3/ugfx|uGFX]] - -== 10. Your own app == - -Having to have your badge connected to your computer all the time is a bit boring. Let's make it an app, so you can carry it around! - -Update your <code>main.py</code> to look like this: - -<source lang="python"> -### Author: Your Name -### Description: Smiley! -### Category: Tutorial -### License: MIT -### Appname : Smiley - -import ugfx -import buttons -import pyb - -ugfx.init() -buttons.init() -ugfx.clear(ugfx.YELLOW) - -ugfx.text(5, 5, "Hello World", ugfx.RED) -ugfx.fill_circle(100, 100, 30, ugfx.GREEN) -ugfx.fill_circle(200, 100, 30, ugfx.GREEN) -ugfx.area(80, 150, 140, 20, ugfx.GREEN) -ugfx.area(120, 170, 60, 20, ugfx.GREEN) - -while not buttons.is_pressed("BTN_MENU"): - pyb.wfi() -</source> - -The bit at the top is a comment, it's not actually part of the code and python ignores it. It does however help us categorise the app. Make sure you update your name :) - -Plug your badge in and open the USB drive. Go into the "apps" folder and create a new folder called "hello_screen". Copy your newly updated <code>main.py</code> into there and safely eject the device. If you now press the reset button at the back of your badge it will restart normally. Wait until your name appears and press the MENU button. Go all the way to the bottom right and select "View all". Now you have to press "right" until you find the "Smiley" app. Select it and press A - You should now see your smiley. - -== 11. Publish your app to the app library == - -Now that you have your own smiley app, why not share it with others? - -Find your main.py and create an archive of it. Most operating systems have something build in for that purpose. In OSX you can right click and select "Compress main.py", under Windows you can select "New > Zipped folder" and drag required files into the zip; under Linux you right click the files and use "Compress...". You should now have a new file called <code>main.zip</code> or similar. - -Go to http://api.badge.emfcamp.org/ and sign up with your email address and a password. In the top right there's a field called "Create New App" - Put "Smiley" into the field next to it and then click "Create". On the next screen click the "Choose File" button and select your <code>main.zip</code>. Now press "Upload" - and you're done! - -You now have to wait until we have reviewed your app to make sure it's not doing something weird and then we'll hit the "publish" button and everyone on the camp site will be able to download your newly created app to their badge. If we're not quick enough, feel free to come to the badge tent and we'll hurry the review up ;) - -= Alternative ways to work with TiLDA = - -All of the python code which runs on the badge can be modified on the mass storage device, and new apps can be added this way too. Be careful when using text editors to modify files on the device, if the mass storage is not 'safely removed' before removal, corruption of the file being edited can occur. - -When writing your own code, it is advised edit code on your computer, then copy it across to the badge, wait for the red 'writing' LED to go out, reset it, and run. -This way you don't need to worry about safely removing the badge each time. - -To interactively run code on the badge, a python REPL can be accessed via the virtual serial port. Once you have found the serial port, use your favourite serial terminal to connect to the badge. Since the badge will be running the main software, press Ctrl+c to stop it, and the badge will display '>>>' to indicate it is ready to receive commands. - -The badge runs micropython, and as a result does not contain everything you may expect from full python. See the micropython docs in the lniks below for more information. -The badge has additional APIs, in particular for the LCD, Wifi and IMU, which are also listed below. - 79gy8cy8zikxd29r31g9dj745x1sf5x - - - - TiLDA MK3/How to fix NeoPixel - 0 - 40 - - - 213 - 2016-08-09T21:50:30Z - - Raj - 23 - - Raj moved page [[TiLDA MK3/How to fix NeoPixel]] to [[TiLDA MK3/NeoPixel]] - 213 - wikitext - text/x-wiki - #REDIRECT [[TiLDA MK3/NeoPixel]] - e3uyksywx2v3hdo1haqia2b8oahrgfx - - - - TiLDA MK3/Ideas - 0 - 24 - - 280 - 179 - 2018-07-06T22:49:35Z - - Chrisstubbs - 49 - - 280 - wikitext - text/x-wiki - -Here are some ideas on what to do, feel free to add your own. If you are working on a project and want some help or want to share, create a new page for the project and link it here. - -== Ideas == -=== Small things === - -- Replace snake's block colours with images - -- Accelerometer ball bounce - -- Network synced clock - -=== Larger projects === - -- IRC relay - --Location based on wifi RSSI ( badge team are looking for someone to write a good library for this) - -- [https://badge.emfcamp.org/wiki/TiLDA_MK3/Ideas/hab High altitude balloon tracker] - -== apps == - -- Network Map for location approximation: [[TiLDA_MK3/apps/nmap|tilda-nmap]] - -- Interactive python prompt - eb2xkxlm92ekul0yoku29wm0h2bp5lq - - - - TiLDA MK3/Ideas/hab - 0 - 55 - - 281 - 279 - 2018-07-07T22:40:40Z - - Chrisstubbs - 49 - - 281 - wikitext - text/x-wiki - -== MK3 High Altitude Balloon tracker == - -'''Goal:''' - -Launch a high altitude balloon at EMF 2018 using a badge tracker. - - -'''Progress:''' - -Tracker parameter setup app (done) - -Get timer working for RTTY transmission interrupt (done) - -Get SPI working with RMF22 for transmitter (done) - -Get UART working for GPS - -Write the tracker code - -Power saving - -Boot directly into tracker code (see USB mouse app code - similar idea) - - -'''Stretch goal:''' - -Camera? SSDV? - - -'''More''' - -[https://wiki.emfcamp.org/wiki/Village:HABville HABville] - rhd9rlfmapy09jcfihebviwd87suopu - - - - TiLDA MK3/Introduction to badge hacking - 0 - 32 - - 259 - 195 - 2017-03-02T01:18:41Z - - Claude - 47 - - /* Beginners Guide to Badge Hacking */ fix broken link to micropython repl tutorial - 259 - wikitext - text/x-wiki - = Beginners Guide to Badge Hacking = - -We're going to create an LED torch for seeing our way around the camp. - -'''Soldering the LED''' - -You should have received an LED and a resistor with your badge. First, grab the resistor. Bend the legs over so they fit in the holes in the board, using the resistor lead bender. - -[[File:Hackpad.com_Rs7awClTQDH_p.554927_1470420913282_legbender.jpg|none]] - -It doesn't matter way round the resistor goes. - -[[File:Hackpad.com_Rs7awClTQDH_p.554927_1470307053798_P1010517.jpg|none]] - -Flip over your board and solder the resistor in place, then trim down the legs to be flush against the board. - -Next, the LED. It does matter which way round the LED goes - look for a flat side on the LED and match it up with the flat side on the board. Pull your LED out about a centimetre and bend it over a bit. - -[[File:Hackpad.com_Rs7awClTQDH_p.554927_1470307470838_P1010533.jpg|none]] - -Flip the board over and solder the LED into place. - -'''Testing''' - -Plug your badge into your laptop, and use the information on [https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html] to connect to the usb-serial port. If you hit Ctrl-C, you drop out of the badge software, and get a REPL prompt. You can tell this is working because you'll see three &gt; symbols. - -Type the following at the prompt. This should turn your LED on! - - import pyb - pin = pyb.Pin(&quot;LED_TORCH&quot;) - pin.high() - -Of course, thats a bit of a pain to do every time we want the LED on, so let's make an app! - -'''The App''' - -Your badge should have shown up as a USB drive. Open the folder '''apps''', and create a folder within it called '''torch.''' - -Create a file within this called '''main.py'''. This is your app's main file. Open it in a text editor. - -First, we need to tell the badge some details about your app. This is done in a header section at the top of the file - - - # Author: Your Name - # Description: Torch - # Category: Flashy - # License: MIT - # Appname : Torch - # Built-in: no - - -You could save and run your app now, but it wont actually do anything yet. Lets add the code: - - - # Author: Your Name - # Description: Torch - # Category: Flashy - # License: MIT - # Appname : Torch - # Built-in: no - - import pyb - pin = pyb.Pin(&quot;LED_TORCH&quot;) - pin.high() - while True: - pass - -Save, and run your app. When you run it the LED should turn on, brill! - -Of course, we're not showing anything on the screen. Lets have a nice notice box to show we're in the torch instead of that while loop. - - # Author: Your Name - # Description: Torch - # Category: Flashy - # License: MIT - # Appname : Torch - # Built-in: no - - import pyb - import ugfx - import dialogs - - pin = pyb.Pin("LED_TORCH") - pin.high() - ugfx.init() - ugfx.clear(ugfx.html_color(0x7c1143)) - dialogs.notice("Shine a light!", title="Torch", close_text="Exit") - -Run your app again and you should have a nice button you can press to shine a light in the camp! - -You can unplug the badge from your computer when the LED has finished flashing, but we recommend you eject the drive first. - ewudnyvs150z6m5sm0ckdb3k55oq9qt - - - - TiLDA MK3/memory problems - 0 - 34 - - 176 - 2016-08-06T14:50:14Z - - Marekventur - 10 - - Created page with "=Call for Help: Memory Issues= Please help the badge team: https://github.com/emfcamp/Mk3-Firmware/issues/71" - 176 - wikitext - text/x-wiki - =Call for Help: Memory Issues= - -Please help the badge team: https://github.com/emfcamp/Mk3-Firmware/issues/71 - 1byzfnibha4156dtuu8veraqv26w1hs - - - - TiLDA MK3/modtilda - 0 - 59 - - - 308 - 293 - 2018-08-29T11:04:10Z - - Davea - 30 - - Redirected page to [[TiLDA MK4/modtilda]] - 308 - wikitext - text/x-wiki - #REDIRECT [[TiLDA_MK4/modtilda]] - ctiluxl36oyjpf5ok3sdqd2oqzkhx4w - - - - TiLDA MK3/NeoPixel - 0 - 37 - - 242 - 221 - 2016-08-24T19:32:24Z - - JasperWallace - 9 - - add some urls to examples. - 242 - wikitext - text/x-wiki - One feature of the Mk3 is a single NeoPixel multi-colour LED adjacent to the red power/charge LED. - -==Faulty manufacture== -Unfortunately, during the original manufacture of the badges the NeoPixel was mounted 180 degrees out of orientation. As originally delivered it will not function, being mounted with the triangular notch facing the outer part of the badge and the chip part of the LED (the brown spot under the transparent plastic) facing the charge LED. The correct position is with the triangular notch facing inward and the chip part facing the "D1" label of the silkscreen. - -===Correcting the faulty mount=== -The best solution should be to use soldering tweezers take the LED off, clean the pads, turn it, and put it on but this is a delicate operation that will probably destroy the LED. The trick is to be quick, to use a fairly high temperature (350-370 degrees) and add some new solder to the pads to increase the heat transfer. - -You can possibly use two soldering irons at the same time, one on each side of the LED. - -Avoid hot air at all costs, the badge is packed and you don't really want to risk blowing the charging LED away or even worse, damaging the LCD. - -==Programming the LED== - -See this: https://github.com/mayhem/tilda-mk3-led-demo/blob/master/main.py - -Or NeoPixelTest in the App Library: http://api.badge.emfcamp.org/app/emuboy/neopixtest - 3icltpcrn6x5flob1kzikohaywtau51 - - - - TiLDA MK3/reset - 0 - 22 - - 253 - 252 - 2017-01-16T11:11:19Z - - Jonty - 45 - - 253 - wikitext - text/x-wiki - Should your badge stop working there are three ways to fix it. Please make sure you have a backup of whatever you've been working on, you might lose all the data stored on your badge. - -It's best to try these in sequence, however if you just want to factory reset your badge skip to option (3). - -# Try deleting the file you have been working on, "safely eject" the badge and then press the reset button. -# Delete all other files apart from <code>boot.py</code>, <code>wifi.json</code> and <code>bootstrap.py</code>, "safely eject" the badge and then press the reset button. -# Factory reset the badge. Press and hold 'MENU' and then press the reset button on the back. Keep the MENU button held down, then release it when both the green light is on and the screen is white. - -All these steps should finally get you to a screen saying "Downloading TiLDA software". It should take less than a minute until the bare badge functionalities are restored. - -P.S. The micropython documentation on factory resetting is [http://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/reset.html here]. On the TiLDA MK3 the USR button is the MENU button, and the orange light is the screen going white. - mko3lo9qnjsly04jnftaztmr2yg4mkp - - - - TiLDA MK3/rtc - 0 - 16 - - 256 - 43 - 2017-03-02T00:52:07Z - - Claude - 47 - - fix broken link to micropython rtc docs - 256 - wikitext - text/x-wiki - The following code snippets demonstrate the RTC. See the micropython docs [https://docs.micropython.org/en/latest/pyboard/library/pyb.RTC.html] for more information. - -<pre> -# Create a RTC object -rtc = pyb.RTC() - -# If the RTC isn't running, call -rtc.init() - -# Set the time -rtc.datetime((2016, 5, 1, 4, 13, 0, 0, 0)) - -# Get the time -print(rtc.datetime()) -</pre> - io0z3k23ppay8ise9gp1qkt0h7w9fvf - - - - TiLDA MK3/Run Code - 0 - 28 - - 260 - 238 - 2017-03-02T01:22:43Z - - Claude - 47 - - /* Option 1: REPL */ fix broken link to micropython repl tutorial - 260 - wikitext - text/x-wiki - This video is meant for the micropython board, but most of it works similar on the TiLDA: https://micropython.org/ - -= Option 1: REPL = -REPL stands for "[https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop Read–eval–print loop]" and allows you to run python code, line by line. This is a great way to see effects of certain hardware commands instantly and to test basic python features. - -This allows you to run code, line by line, on the badge and to see the effects instantly. Follow https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html or follow step 1-4 on the [[TiLDA_MK3/Get_Started|Get Started]] guide. - -<strong>Note:</strong> This will only work if you have an empty <code>main.py</code> on your badge to stop the home screen from taking over instantly. If an app or script is already running you will not get a REPL that you can use to program, but simple debug output instead. Remember to remove it afterwards if you want to use the home screen again. - -You can also press Ctrl-C to stop the currently running app and get to the python prompt. - -= Option 2: Copying files = -You can also copy your code to <code>main.py</code> on your badge, safely eject and then reset the badge via the button. To debug it you can use the serial console (see option 1) which will show you all text printed via <code>print()</code> and errors. - -<strong>Note:</strong> It's very important to always correctly "eject" the usb storage before pressing the reset button, otherwise your filesystem is going to corrupt and you might have to [[TiLDA_MK3/reset|factory reset]] your badge - -Remember to remove your main.py afterwards if you want to use the home screen again. - -On Linux you can use this script to automatically mount the TILDA -> sync files from a local directory -> safely eject: https://gist.github.com/IVBakker/fbab508c336397323d6c1caef8cdc46c - -= Option 3: pyboard.py = -You can also use micropythons's <code>pyboard.py</code> script to automatically run a full local file of code without having to worry about copying it line-by-line or ejecting your device. - -You can find a quick introduction on how to set it up [https://badge.emfcamp.org/wiki/TiLDA_MK3/Get_Started#5._Run_a_whole_file_of_code here]. - -This option is very useful as a build script with your editor, it allows you to quickly test whether your app is working. - -<strong>Note:</strong> While this option works even if you run the home screen, it works slightly better if you have an empty <code>main.py</code> on your badge. - -=== Sublime Text 2 build script === -OSX: -<pre> -{ - "shell_cmd": "/path/to/your/pyboard.py --device /dev/tty.usbmodem* $file" -} -</pre> - pu2f8k7omvymvgqjr2n3ep139dbwc80 - - - - TiLDA MK3/spi - 0 - 56 - - 283 - 282 - 2018-07-07T22:48:49Z - - Chrisstubbs - 49 - - 283 - wikitext - text/x-wiki - See here [https://docs.micropython.org/en/latest/pyboard/library/pyb.SPI.html] for the main micropython documentation. - -SPI1 is used for the board's onboard wifi. - -SPI2 is exposed on the 'X' header, under the white silkscreen section for your name. - - -<pre> -from pyb import SPI - -spi = SPI(2) #create SPI on port 2 -spi.init(SPI.MASTER) #set the mode. Other things like baudrate=80000, polarity=1, phase=0, crc=None can be set here - -spi.send(170) #send int byte -spi.send(b'\xAA') #send hex byte -</pre> - gpr7rluh1mbdh168ixprfcu0b8n7o5v - - - - TiLDA MK3/subtree - 0 - 15 - - 41 - 2016-07-07T17:33:19Z - - Marekventur - 10 - - Created page with "= UGFX subtree management = The folder UGFX is a subtree tracking git@bitbucket.org:mattbrejza/ugfx.git. Please don't edit anything in there directly unless you know what you'..." - 41 - wikitext - text/x-wiki - = UGFX subtree management = -The folder UGFX is a subtree tracking git@bitbucket.org:mattbrejza/ugfx.git. Please don't edit anything in there directly unless you know what you're doing. - -Read https://medium.com/@porteneuve/mastering-git-subtrees-943d29a798ec for more information on the topic. - -== Prerequisites== -<pre> -git remote add ugfx git@bitbucket.org:mattbrejza/ugfx.git -</pre> - -== How it's set up== -<pre> -git read-tree --prefix=extmod/ugfx -u ugfx/master -git commit -m "..." -</pre> - -== How to update the subtree== -<pre> -git fetch ugfx -git merge -s subtree --squash ugfx/master -git commit -m "Update UGFX subtree to ..." -</pre> - h4rl52817cxtp8lw75ifjhamp9jyyc1 - - - - TiLDA MK3/timer - 0 - 20 - - 278 - 257 - 2018-07-06T22:23:59Z - - Chrisstubbs - 49 - - 278 - wikitext - text/x-wiki - See the micropython documentation [https://docs.micropython.org/en/latest/pyboard/library/pyb.Timer.html] for a detailed explanation. Some examples are below. - -Note that when your program completes executing, the badge will restart back to the main menu. If your program doesn't do anything else after initialising the timer, the badge will look like it just restarts when you run your program! If you just want the timer callback to keep running and do nothing else, end your program with a loop like "while True: pass". - -== Function callbacks == - -<pre> -flag = 0 - -#note, this callback needs to take one parameter, which is what timer is calling it -def tim_callback(t): - global flag - flag = 1 - -timer = pyb.Timer(3) -timer.init(freq=1) -timer.callback(tim_callback) - -.... - -timer.deinit() -</pre> - -or, using lambdas - -<pre> -flag = 0 - -#the use of lambda avoids needing the function to take an argument -def tim_callback(): - global flag - flag = 1 - -timer = pyb.Timer(3) -timer.init(freq=1) -timer.callback(lambda t: tim_callback()) - -.... - -timer.deinit() -</pre> - gh11fwf3ibjja8jfrffoppuy4xst8n5 - - - - TiLDA MK3/ugfx - 0 - 13 - - 286 - 241 - 2018-08-12T17:47:23Z - - Binney - 50 - - wrong function name in example, maybe was copypasta originally? - 286 - wikitext - text/x-wiki - The badge makes use of [http://ugfx.io uGFX] for providing drawing functions on the LCD. Most of this functionality is available through the micropython interface, and you may wish to browse the [https://wiki.ugfx.io/index.php/Main_Page uGFX documentation] for more details. - -To discover exactly which ugfx calls are available in micropython, see https://github.com/emfcamp/micropython/blob/tilda-master/stmhal/modugfx.c - -== Basic usage == - -uGFX is comprised of 'widgets,' such as buttons and labels, and 'containers' which are used to group widgets. - -To create a button on the screen, use <code>ugfx.Button(x,y,width,height,text)</code>, and a button will be drawn on the screen. - -As well as widgets, there are 'primitives' such as drawing circles and lines, which can be drawn anywhere on the screen or in a container. -For example <code>ugfx.circle(50,50,20,ugfx.RED)</code> will draw a circle. - - - -== Detailed documentation == - -Note. all co-ordinates are from the top left (battery symbol) corner. All widgets are created from the "ugfx" package, eg: ugfx.Contailer(). - -=== Colour format === - -Internally, ugfx uses 565 format (5 bits for red and blue, 6 for green). Preset colours are available, for example '''ugfx.RED''', '''ugfx.ORANGE''', etc. To convert from 24 bit RGB format, use '''ugfx.html_color(0xRRGGBB)''' to return the 16 bit 565 format. - -=== Styles and Fonts === -Use <code>ugfx.set_default_font(...)</code> to change the font. The font options are: -* ''ugfx.FONT_SMALL'' -* ''ugfx.FONT_MEDIUM'' -* ''ugfx.FONT_MEDIUM_BOLD'' -* ''ugfx.FONT_TITLE'' -* ''ugfx.FONT_NAME''. -Note that widgets use the font which was default when they were created, while the ''container.text()'' primitive uses the font that was default when the container was created - -=== Containers === - - .Container(x, y, width, height {,style}) # the style is optional - -Containers can be used to group widgets together. They can also perform primitive drawing functions. When drawing widgets or primitives, the coordinates are relative to the top left corner of the container. - -Containers can be shown or hidden, and all the widgets will be redrawn. Containers can also be placed on top of other widgets. When the top container is hidden, the widgets below will be redrawn. - -Upon creation a style can be passed to a container, which will then be used by default by widgets created as part of that container. If no style is specified at creation, the current default style will be used. - -The following example shows how to create a container, add an object and show it. -<pre> -c = ugfx.Container(100,100,200,100) -b = ugfx.Button(10, 10, 40, 30, "OK", c) -c.show() # the container will not be shown until this point -</pre> - -=== Primitives === -All primitives can be drawn anywhere on the screen with, for example <code>ugfx.circle(..)</code>, or anywhere within a container, with <code>c=ugfx.Container(30,30,100,100); c.circle(..)</code> - -==== Clear ==== - -<code>.clear(colour = ugfx.WHITE)</code> - -clears the screen to the specified colour. Warning, this is slow! - -==== Lines ==== -<code>.line(<x1>, <y1>, <x2>, <y2>, <colour>)</code> - -<code>.thickline(<x1>, <y1>, <x2>, <y2>, <colour>, <width>, <round>)</code> - -Draws a line from ''x1,y1'' to ''x2,y2'' using ''colour''. Thickline will draw a line or arbitrary width, with the option of rounded corners - -eg. ''ugfx.thickline(0,0,100,170,ugfx.YELLOW,7,0)'' - -==== Circle ==== -<code>.circle(x, y, diameter, colour)</code> - -<code>.fill_circle(x, y, diameter, colour)</code> - -Draws a circle at ''x,y'' of <diameter> using ''colour'', either with a 1 pixel border or filling the area. - -eg. ''ugfx.circle(180,150,40,ugfx.RED)'' - -==== Arc ==== -<code>.arc(x, y, r, angle1, angle2, colour)</code> - -<code>.fill_arc(x, y, r, angle1, angle2, colour)</code> - -Similar to the circle functions, however two angle parameters specify between which two angles drawing occurs - -==== Ellipse ==== -<code>.ellipse(x, y, a, b, colour)</code> - -<code>.fill_ellipse(x, y, a, b, colour)</code> - -Draws an ellipse at ''x,y'' of ''a'' width and ''b'' height using ''colour'', either with a 1 pixel border or filling the area. - -==== Rectangles ==== -<code> .box(1, y, a, b, colour) </code> - -<code> .area(x, y, a, b, colour)</code> - -Draws a rectangle or filled rectangle at ''x,y'' of ''a'' width and ''b'' height using ''colour''. - -==== Polygon ==== -<code> .polygon(x, y, array, colour) </code> - -<code> .fill_polygon(x, y, array, colour) </code> - -Draws or fills a polygon starting at ''x,y'' using ''colour''. ''Array'' is an array of coordinates that specifies the corners. - -eg. ''ugfx.polygon(0,0, [ [0,20],[20,20],[20,0]], ugfx.RED)'' - -==== Text ==== -<code>.text(x, y, text, colour) </code> - -Draws a text string ''text'' at ''x,y'' in ''colour''. -Note that a ugfx.text(..) call will take the default font, while container.text(..) will take the containers font. - -eg. ''ugfx.text(40,40,"My name is...",ugfx.BLUE)'' - -==== Other ==== -<code>.width()</code> - -<code>.height()</code> - -Gets the height or width of the screen ''ugfx.width()'' or container object ''c.width()'' - -=== Widgets === - -Widgets can be drawn anywhere on the screen, or within a container. The widgets take the optional parameter ''parent='' to set the parent container. Widgets can have their style set on creation, otherwise will inherit - -Widgets also accept input from the buttons. For example, the 'A' button can be 'attached' to an on-screen button, such that pressing the button on the badge causes the on-screen button to be redrawn in a depressed state. - -==== Common Widget methods ==== - -<code>.text([text])</code> - -Gets or sets the text displayed by the widget. - -<code>.visible([show])</code> - -Gets or sets the visibility of the badge. ''b.visible(0)'' will hide, and ''b.visible(1)'' will show. - -<code>.attach_input(button, function)</code> - -Attaches a physical button to a widget, so that the user can cause the widget to redraw, for example to scroll or become depressed. - -The input ''button'' specifies which button, with the options ugfx.BTN_A, ugfx.BTN_B, ugfx.BTN_MENU, ugfx.JOY_UP, ugfx.JOY_DOWN, ugfx.JOY_LEFT, ugfx.JOY_RIGHT. - -The input ''function'' specifies what the button actually does. For example, the list has three different functions: scroll up, scroll down, and select. Note that some widgets by default attach the joystick to the relevant functions. - -<code>.detach_input(function)</code> - -Detaches an input. See above for more details. - -<code>.destroy()</code> - -Frees up all the resources assoicated with the object. While the micropython garbage collector will clear any old objects, the graphics library also has its own memory area, which can become full if objects are not destroyed after they are needed. - -<code>.set_focus()</code> - -Gives focus to the widget instance. Normally this will draw a box around the widget, the colour is specified by the style. - -==== Button ==== - -<code> b=ugfx.Button(x, y, w, h, text, *, parent=None, trigger=None, shape=ugfx.Button.RECT, style=None) </code> (note: parameters after '*' are optional) - -Draws a button at ''x,y'' having width ''a'' and height ''b''. The option 'trigger' specifics which physical switch (if any) causes the display to be redrawn. The shape options are ''ugfx.Button.RECT'', ''ugfx.Button.ROUNDED'', ''ugfx.Button.ELLIPSE'', ''ugfx.Button.ARROW_UP'', ''ugfx.Button.ARROW_DOWN'', ''ugfx.Button.ARROW_LEFT', ''ugfx.Button.ARROW_RIGHT''. - -==== Textbox ==== -<code> ugfx.Textbox(x, y, w, h, *, text=None, parent=None, maxlen=255})</code> - -Draws a text edit-box which can take input from the on-screen keyboard. Will automatically accept key-presses from the keyboard, which will edit the text. The textbox needs to have focus using .set_focus() for it to receive the key-presses. - -==== Checkbox ==== - -<code>.Checkbox((x, y, w, h, text=None, parent=None, trigger=None, style=None)</code> - -<code>.checked()</code> - -Get or set the checked state - - -==== Label ==== - -<code> ugfx.Label(x, y, w, h, text, *, parent=None, style=None, justification=None)</code> - -A label displays text. Unlike the primitive text, this Label supports different justifications, wordwrap and changing text. The different justification options are ''ugfx.Label.LEFT'', ''ugfx.Label.RIGHT'', ''ugfx.Label.CENTER'', ''ugfx.Label.LEFTTOP'', ''ugfx.Label.RIGHTTOP'' and ''ugfx.Label.CENTERTOP''. - -==== List ==== - -<code>ugfx.List(x, y, w, h, *, parent=None, up=ugfx.JOY_UP, down=ugfx.JOY_DOWN, style=None)</code> - -<code>.enable_draw()</code> - -<code>.disable_draw()</code> - -<code>.add_item(text)</code> - -<code>.assign_image(index, image)</code> - -<code>.remove_item(index)</code> - -<code>.selected_text()</code> - -<code>.selected_index()</code> - -<code>.count()</code> - -==== Graph ==== - -<code>ugfx.Graph(x, y, w, h, origin_x, origin_y)</code> - -<code>.show()</code> - -<code>.hide()</code> - -<code>.set_arrows(ugfx.Graph.ARROWS_X_POS | ugfx.Graph.ARROWS_Y_POS)</code> - -Set which axes have arrows and in which direction. In this example arrows are set for the x and y positive directions, with the following options available: ARROWS_X_POS, ARROWS_Y_POS, ARROWS_X_NEG, ARROWS_Y_NEG - - -<code>.plot( point(s)_x, point(s)_y, {new_series} )</code> - -Plot either an array, or a point. Optional second parameter specifies whether to start a new series or join onto previous. - - -<code>.appearance( thing_to_change, shape, size, colour, {spacing} )</code> - -Changes the style of either points, lines, axis or grids. Each parameter is used as follows: - -'thing_to_change' - select what aspect to change, the options are {STYLE_POINT, STYLE_LINE, STYLE_XAXIS, STYLE_YAXIS, STYLE_XGRID, STYLE_YGRID} - -'shape' - selects the shape of the thing to change, where the options depend on what you are changing. -The options for points is: {POINT_NONE, POINT_DOT, POINT_SQUARE, POINT_CIRCLE} -The options for line/axis/grid are: {LINE_NONE, LINE_SOLID, LINE_DOT, LINE_DASH} - -'size' - number of pixels wide of the thing to change - -'colour' - use UGFX.Red, UGFX.Orange,... or UGFX.html_color(0xRRGGBB) to ensure the right format - -'spacing' - only valid for grid - -See the [https://github.com/emfcamp/Mk3-Firmware/blob/master/apps/logger/main.py BARMS logger app] for an example - -==== ImageBox ==== - -<code>.ImageBox(x, y, w, h, filename, *, cache=0, parent=None, style=None)</code> - -==== Keyboard ==== - -<code>.Keyboard(x, y, w, h, parent=None)</code> - -=== Styles === -<pre> -s=ugfx.Style() # create a style based on the current default style - -s.set_enabled([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is enabled -s.set_pressed([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is pressed -s.set_disabled([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is disabled - -s.set_focus(colour) # sets the colour used for focus -s.set_background(colour) # sets the background colour for the style - -ugfx.set_default_style(s) # use this style from now on - -b=ugfx.Button(0,0,40,30,"OK", style=s) # use the style for this button - -</pre> - -== Tips and tricks == - -=== Tearing === - -When writing large areas of the screen, a 'tearing' [https://en.wikipedia.org/wiki/Screen_tearing] effect may be observed. - -The screen module is comprised of a large memory, with one memory location to store the RGB data for each pixel. The LCD driver continuously updates the LCD pixels, by reading the memory in a sequential, line-by-line manner, and updating the LCD with the data from the memory. This 'read line-pointer' moves from the top to the bottom of the screen (when viewed in portrait), at about 70Hz (the refresh rate of the screen) - -This large memory as part of the screen means it can be driven by a microcontroller which may have a considerably smaller memory. The microcontroller therefore only needs to update the memory when it whats the content to change. - -Consider the scenario where the microcontroller wants to set the screen from one colour to another. The microcontroller needs to update the entire memory (320x240x2 = 153kB) with the new colour. At the same time the 'read line-pointer' is reading the same memory to update the LCD. In this case, tearing occurs if the 'read line-pointer' reads the top half of the memory containing the new colour, but then catches up with microcontroller writing to the memory, then the 'read line-pointer' starts reading the old colour in the bottom half of the memory. - -To avoid tearing the 'read line-pointer' should not cross the region the microcontroller is updating. Since the microcontroller writes to the screen slightly slower than the LCD reads it, providing the microntroller starts writes to the top of the memory just after the LCD starts reading from the top, the read and write pointers will not overlap, and tearing will not occur. To sync the microcontroller with the LCD 'read line-pointer,' there is a vsync/tear output (connected to pin named 'TEAR') which is pulled high when the 'read line-pointer' reaches a given line (default is line 0). This can be turned on and off with '''ugfx.enable_tear()''' and '''ugfx.disable_tear()'''. To change the line at which the tear output is generated, use '''ugfx.set_tear_line(0..319)'''. - -Example code: - - ugfx.enable_tear() - tear = pyb.Pin("TEAR", pyb.Pin.IN) - - def vsync(): - while tear.value() == 0: - pass - while tear.value(): - pass - -=== Reducing power consumption === -Use the following to dim the backlight, which uses about 80mA at full brightness -<pre> -ugfx.backlight(b) # sets the backlight. Range is 0-100 -b = ugfx.backlight() # reads the current backlight -</pre> - -== Top-Level calls == - -<code>.power_mode(<mode>)</code> - -''mode'' can be any of: ugfx.POWER_ON, ugfx.POWER_OFF, ugfx.POWER_DEEP_SLEEP, ugfx.POWER_SLEEP - -<code>.orientation(deg)</code> - -Rotate the display by number of degrees, eg 180 for upside-down. - -Calling with no args returns the current value - -<code>.display_image(x, y, '/path/to/image', orientation)</code> -<code>.display_image(x, y, img_obj, orientation)</code> - -Display an image from a file of a supported type, or a previously opened image object, on screen at the x,y co-ordinates. Optionally change its orientation. - -<code>.write_command(0x35,0)</code> - -Low-level command to write to a data register directly. - -<code>.poll()</code> - -Yield to ensure the screen is redrawn when waiting on user input - -<code>.ball_demo()</code> - -Ball Demo! - -<code>.get_pixel(x, y)</code> - -Returns the colour of the pixel at x,y - -<code>.Image(filename, cacheme)</code> - -Creates and returns (or loads from cache) a ugfx image object from the image in the filename. - q5en5v2yoa6pl9dess0vxwtoowgrly7 - - - - TiLDA MK3/wifi - 0 - 19 - - 148 - 118 - 2016-08-06T07:42:15Z - - Marekventur - 10 - - /* wifi.json */ - 148 - wikitext - text/x-wiki - = wifi.json = -A simple json document in the root directory of the badge: -<pre> -{"ssid":"your-wifi-name","pw":"your-wifi-password"} -</pre> - -If you're connecting to an open wifi you can leave out the "pw" : -<pre> -{"ssid":"your-unsecured-wifi-name"} -</pre> - -Most badge apps that use the wifi chip will expect a wifi.json file to exist. Please make sure it's valid json and that both name and password are in the correct case. - -Please make sure to "eject" the usb storage properly before restarting the badge. - 759sm5assqkgokc6ao4wxnlmlf5fg0w - - - - TiLDA MK4 - 0 - 57 - - 482 - 467 - 2024-03-28T09:55:40Z - - Raj - 23 - - 482 - wikitext - text/x-wiki - [[File:TiLDA_Mk4_Front_with_sponsors.png|right|500px|TiLDA Mk𝛿]] - -== Using your badge == - -<div style="background-color: #FFFFDD; border: 1px solid #808000; padding: 5px;"><strong>If you just got your badge and it doesn't do anything</strong>, don't despair, quite a few of them need to be [[TiLDA_MK4/reset|factory reset]] before showing the loading screen. Press and hold <code>MENU</code> while quickly pressing the reset button at the back. Keep the <code>MENU</code> button hold for another 2 seconds. Release it when both the red and green LED are lit. If you got it correct both LEDs should flash a few times.<br>If this doesn't work you can [[TiLDA_MK4/Firmware_Update|update the badge firmware]]. If this doesn't work, please come and join us in #emfcamp-badge on [https://libera.chat/ Libera IRC]</div> - -=== Updating your badge firmware === -After (and during!) EMF the badge firmware was substantially fixed and improved, resolving issues with call handling and apps. - -Please update your badge firmware as soon as possible. You can find [[TiLDA_MK4/Firmware_Update|documentation on this here]]. - -=== Assembly === -With your badge you will receive a booklet explaining how it's done. If you have any problems, please come to the Badge Operation Center and we will help you.<br> -Booklet can be found [https://archive.org/details/emf2018_badge_guide here] - -=== Basic usage === -After you have assembled your badge you can just use the tiny switch at the bottom of the screen to turn your badge on. Alternatively you can use any USB power source. If you turn your badge on for the first time (or if for some reason it has reset itself) you will get some on-screen information while we try to download the newest set of software. '''This doesn't always work on the first try, you might have to use "reset" to try a few times''' - -If at any point you want to restart your badge you can just press the reset button on the back below the display ribbon. - -==== Changing your name ==== - -# Press 'Menu' -# Select the 'Settings" app -# "Change Name" and press 'A' -# Use the joystick and 'A' key to enter your name -# Press 'Menu' to save your name and reset the badge - your name should now be displayed! - -==== Installing new apps ==== - -# Press 'Menu' -# Select 'Badge Store' app and press 'A' -# Select "Install" -# Select a category and then an app. Wait until you see the description and press "A" to save it. -# Press B a few times (or alternatively MENU) to restart your badge -# On the home screen you can now press MENU to find your newly installed app. - -=== WiFi === -Your TiLDA Badge has built-in wifi support. It should all just work if you're at the campsite, but if you're on your own network you might have to tell the badge about it. For more information please have a look here: [[TiLDA MK4/wifi|WiFi]] - -=== Charging === -The badge charges via a microUSB socket, and takes about 2-3 hours for a full charge. The red charge LED to the right of the display ribbon on the back will extinguish when charging is complete. - -=== Calling and SMS === - -'''Warning: The badge team are aware of an issue of instability while using the calling capability. Please bear with us while we diagnose this.''' - -Yes your TiLDA Badge is also a mobile phone. To connect to the EMF mobile network insert the Hologram SIM supplied, load the "phone" app, select "Select Operator", wait, wait some more, and a little longer, then select "EMF" or "23404". Select "Auto" to use a public mobile network again. - -To find out your number on the EMF network select "Information" in the phone app. If "Operator" is not shown on the information screen then you have failed to connect to the network. If you are not given a number then wait a little longer and try again. You can read and send SMS messages with the "sms" app. You can also answer calls by pressing "Call" in any app, and end or reject a call using the "End" button at any time. - -<Radiocode> The cellular part of the badge seems to work (reliably) perfectly if an external antenna is used, such as a mag-mount with a length of coax. Seems to be an EMC issue, as using the pictured right angle antenna directly on the SMA does not work reliably. Time to get the Kapton tape and copper foil out... - -[[File:GSM Antenna.jpg]] - -=== Connecting over USB === -By default, the software is in a loop. If you want to interact over the REPL you need to exit this. The easiest way is to press Ctrl-C. - -It's hard to press Ctrl-C in minicom, so on Linux this is easier to do with screen: -<pre> -screen /dev/ttyACM0 115200 -</pre> - -If you can connect but Ctrl-C has no effect then it is possible that another service on your machine is accessing the tty before you can connect. A likely candidate is modemmanager. You can check if ModemManager is running using: - -<pre> -systemctl | grep -i modem -</pre> - -and can be stopped with: - -<pre> -systemctl stop ModemManager.service -</pre> - -On Mac: -<pre> -screen /dev/tty.usbmodemTiLDA2 -</pre> - -To exit screen, press Ctrl-A, then k, then y. - -On Windows: -# If you don't have PuTTY or a similar program, get PuTTY installer from [https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html] -# Open PuTTY and select Serial connection -# Change COM1 to the COM port for your badge (You can usually find this as USB Seiral Port under ports in device manager) -<font color="#606060"><i>Note: if your badge resets while putty is open, you will have to close the window and open a new connection to the same COM port.</i></font> - -The basic process is this: - -# Connect device to computer with usb -# Fire up minicom or screen -# Press reset button on device -# Hit Ctrl+C quickly and with vigour to get to the REPL before the UI comes up - -=== Nothing works! Help! === - -Don't worry, you can always "factory reset" your badge. Please follow these instructions: [[TiLDA_MK4/reset|Resetting]] - -If everything else absolutely fails, you can try following these instructions (advanced): [[TiLDA_MK4/Firmware_Update]] - -== Hacking your badge == - -=== App Hack === - -'''[https://gist.github.com/SteveAmor/8c333927fded2339da54ad4aaa765d7e A method to hack your app onto your badge]''' - -=== Tilda Tools === - - -'''[[TiLDA_MK4/tilda-tools|tilda-tools]]''' - Should now work on Windows, Linux and OSX - -=== OSX === - -Mass storage now works on OSX - - -'''[[TiLDA_MK4/Introduction_to_badge_hacking|Badge Hacking Workshop Documentation]]''' - - -One of the main goals of TiLDA is to make hacking it as easy as possible. All you need to do so is a computer with USB and your badge. - -* '''[[TiLDA_MK4/tilda-tools|tilda-tools]]''' - the one-stop interface for all your badge needs -* '''[[TiLDA MK4/Get Started|Step-by-step]]''' - to make it as easy as possible to get going -* '''[[TiLDA MK4/Run Code|3 Ways to run code on your TiLDA]]''' -* '''[[TiLDA MK4/Badge Store Submissions|Badge Store Submissions]]''' - Share your creations with others -* '''[[TiLDA MK4/Code Structure|Code Structure]]''' - How the python code is structured - -The badge itself runs code written in the computer language [https://en.wikipedia.org/wiki/Python_(programming_language) Python] which is run by a bit of software called [https://micropython.org/ Micropython]. - -For more information about the functions available please have a look at the [[#Badge API|Badge API]] section of this page. - -In case you're more interested in what makes the hardware tick and your confident with C++ and microprocessors then you can work directly with the micropython code that runs TiLDA: [[TiLDA MK4/build|How to build the firmware from scratch]] - -All code used is hosted on Github. Contributions and PR are very welcome! -* https://github.com/emfcamp/Mk4-Apps -* https://github.com/emfcamp/Mk4-Backend (powers the badge store) -* https://github.com/emfcamp/Mk4-micropython-board - -=== Building Micropython Firmware === -[[TiLDA_MK4/BuildingFirmware|Build Instructions]] - -=== Some ideas === - -[[TiLDA MK4/Ideas|Please share what you've done (or want to do) with others!]] - -Tips by Ben Woodley (Tested on Ubuntu 18.04 and Debian Stretch) - -'''If you're having issues with getting the python prompt while using a serial terminal or the tilda_tools is failing''' -Error displayed: SerialTimeoutException: Write Timeout -Fix: -* Do this command (ModemManager steals your escape characters!) -* $ sudo systemctl stop ModemManager.service -* Then make sure your badge is in an app (anything but the purple home screen) -* Try open a serial terminal with the device (e.g. screen /dev/ttyACM0 115200) -* The issue should not persist - -'''Reflash the firmware''' -* If lets say you wanted to '''force a firmware update to apply the patch for making phone calls''' then just follow these steps. -* $ git clone https://github.com/micropython/micropython.git -* $ cd micropython/ports -* $ git clone https://github.com/emfcamp/Mk4-micropython-board.git -* $ cd Mk4-micropython-board -* $ ./inst_tools -* $ make -* You may need additional packages depending on your distro, follow the errors if encountered with inst_tools or make. -* Put the badge in DFU mode (press and hold the centre button of the joystick and press reset button, let go of joystick after a second) -* $ make flash-dfu -* This will reflash the firmware, if it fails your board is either not in dfu mode or you need additional packages (like python3-serial in apt!) - -'''Using the Grove Serial connector''' - -<Radiocode> -The Badge Team thoughtfully chose to include a couple of Seeed Studio Grove system connectors to the 2018 badge. Looking at the rear of the badge, -they are either side of the unpopulated 3.5mm jack footprint, top right. -*On the left is the Grove I2C connector <anyone using this?> -*On the right is the Grove UART connector -The Grove UART is helpfully labelled "UART4". To use it in Python, it is actually number 2!!! - -Example: - -import machine - -u = machine.UART(2, 9600) - -g = u.readline() - -etc... - -can be used to communicate with the Seeed Studio GPS module. [Seeed Studio: http://wiki.seeedstudio.com/Grove-GPS/] - -== Badge API == - -=== Build-in === -* [http://docs.micropython.org/en/latest/pyboard/ documentation] - General Micropython libarary -* [[TiLDA MK4/ugfx|uGFX]] - The TiLDA LCD colour screen -* [[TiLDA MK4/documentation/cc3100|CC3100]] - The wifi chip -* [[TiLDA MK4/rtc|RTC]] (real time clock) -* [[TiLDA MK4/sensors|Sensors]] -* [[TiLDA MK4/sim800|SIM800]] (GSM/Phone/Bluetooth) -* [[TiLDA MK4/modtilda|import tilda]] (our custom micropython module) -* [[TiLDA MK4/spi|SPI]] SPI -* [[TiLDA MK4/Neopix|Neopix]] WS2812B LEDs -* please add - -=== TiLDA Libraries === -On top of the build-in modules above we have also created a bunch of helpful libraries written in python. If you go through the bootstrap process or use the App Library you should always have a full set of those on your badge. If for some reason this isn't the case you can download our repository from https://github.com/emfcamp/Mk4-Firmware and copy the <code>lib</code> folder onto your badge. - -for now please have a look at the libraries themselves: https://github.com/emfcamp/Mk4-Apps/tree/master/lib - -(feel free to add additional ideas, and create links new wiki pages to on-going projects, perhaps someone will want to contribute) - -=== Hardware === - -Full hardware files are on GitHub [https://github.com/emfcamp/Mk4-Hardware] - -== Badge hardware == - -TiLDA comes with a long list of very useful hardware. Some might be obvious, but some are a bit hidden. -* Texas Instruments [http://www.ti.com/product/MSP432E401Y MSP432E4 SimpleLink Microcontroller] (ARM Cortex-M4F @ 120MHz) -* Texas Instruments [http://www.ti.com/product/CC3120 CC3120 SimpleLink Wi-Fi® Network Processor] -* 256KB internal RAM / 8MB external SDRAM -* 1MB internal flash (firmware) / 1MB external flash (filesystem) -* [https://simcom.ee/modules/gsm-gprs/sim800c/ SIM800 Quad-band GSM/GPRS module] with Bluetooth support -* [https://cdn.hackaday.io/files/11178478239552/ER-TFT024-3_Datasheet.pdf 240x320 RGB screen] -* 2 [https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf WS2812B RGB LEDs] (aka Neopixels) with a 3-pin header to connect your own (And this year they’re the right way up!) -* Texas Instruments [http://www.ti.com/lit/ds/symlink/hdc2080.pdf HDC2080 Low Power Humidity and Temperature Sensor] -* Texas Instruments [http://www.ti.com/lit/ds/symlink/tmp102.pdf TMP102 Digital Temperature Sensor] -* Texas Instruments [http://www.ti.com/lit/ds/symlink/opt3001.pdf OPT3001 Digital Ambient Light Sensor] -* Texas Instruments [http://www.ti.com/lit/ds/symlink/drv5055.pdf DRV5055 High Accuracy Bipolar Hall Effect Sensor] -* Speaker and Microphone -* 2000mAh Battery -* Onboard Ethernet (requires breakout) -* A [https://en.wikipedia.org/wiki/T9_(predictive_text) T9] number keypad and a joystick -* 2 [http://wiki.seeedstudio.com/Grove_System/ Seed Studio Grove headers] (one UART, one I²C) -* [https://learn.sparkfun.com/tutorials/sewing-with-conductive-thread Conductive thread] points and 0.1" header for power/UART/I2C/GPIO -* [https://hackaday.io/project/52950-defcon-26-shitty-add-ons Defcon 26 Shitty Add-Ons connector] - -Hardware files are available on GitHub [https://github.com/emfcamp/Mk4-Hardware]. - -[[File:Sensor_graphic_-_with_fixed_transparency-01.png|left|500px|TiLDA Mk𝛿 Back]] -[[File:Sensor_graphic_-_with_fixed_transparency-02.png|left|500px|TiLDA Mk𝛿 Back]] -[[Category: Badges]] - mj3875vfbnv7i97ucm1mop71jwg9onx - - - - TiLDA MK4/Badge Store Submissions - 0 - 62 - - 435 - 334 - 2018-09-09T16:24:50Z - - Davea - 30 - - /* Headers */ - 435 - wikitext - text/x-wiki - == Rules for apps in the official badge store == - -* App has to be "Rated G: General Audiences – all ages admitted" -* App should not be of malicious nature -* App complies with EMF's [https://www.emfcamp.org/code-of-conduct Code of Conduct] -* No code/image hot-loading without good reasons (since it might be change after the review process) -* It's fine for people to improve on Apps other have written. Likewise, if you submit an App, be aware that others can and will make changes to it. - -== Packaging up your badge app for submission to the store == - -Every app becomes a new folder in the root of the Mk4-App GitHub repository. So if you create a "snake" app, you need to put your program files in a folder called "snake" with at least a "main.py" in it. - -App names need to be unique (the folder structure enforces that). App folders can contain multiple files (python and non python), but at a minimum "main.py" with the correct headers is required. - -Plesae verify that your apps folder structure is correct by running "./tilda_tools validate" (this works without a badge) before submitting it to the badge app store as the validations is also run by Travis to check pull requests. - -=== Headers === - -main.py headers: - -<pre> -___title___ = "<your_app_name>" -___license___ = "MIT" -___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep"] -___categories___ = ["<see below>"] -___bootstrapped___ = True # Whether or not apps get downloaded on first install. Defaults to "False", mostly likely you won't have to use this at all. -</pre> - -Please use one of these categories: -* System -* Homescreens -* Games -* Sound -* EMF -* Villages -* Phone -* LEDs -* Sensors -* Demo -* Other - -== Submitting your badge app to the official badge store == - -* Create a GitHub account [https://github.com/join] -* Download and install git on your local computer [https://git-scm.com/downloads] -* Set up git on your local computer with your username and email address [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#using-git-and-github-to-submit-your-badge-app] -* Fork the emfcamp/Mk4-Apps repo [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#using-git-and-github-to-submit-your-badge-app] -* Clone '''your''' GitHub repo to your computer [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#using-git-and-github-to-submit-your-badge-app] -* Add your app to your local repo [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#using-git-and-github-to-submit-your-badge-app] -* Create a Pull Request [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#using-git-and-github-to-submit-your-badge-app] - -* Over time, your GitHub repo will get out of sync with the changes that have been made to the emfcamp/Mk4-Apps repo so you will need to update your GitHub repo [https://github.com/emfcamp/Mk4-Apps/blob/master/CONTRIBUTING.md#updating-your-github-and-local-git-repo] - -If you prefer a GUI interface, you could consider https://desktop.github.com/ - 33jk3tfjy0x3w4z1olb7davrlr7oya9 - - - - TiLDA MK4/BuildingFirmware - 0 - 76 - - 409 - 407 - 2018-09-02T12:15:34Z - - Drrk - 12 - - 409 - wikitext - text/x-wiki - MacOS and Linux, Windows Builds unknown - -git clone --recurse-submodules https://github.com/micropython/micropython.git - -cd micropython - -git submodule add git@github.com:emfcamp/Mk4-micropython-board.git ports/ti - -cd ports/ti - -./inst_tools - -make - cndtbv8kc2j3ai92s718qt30jp2l3b1 - - - - TiLDA MK4/Code Structure - 0 - 71 - - 434 - 369 - 2018-09-09T16:24:35Z - - Davea - 30 - - 434 - wikitext - text/x-wiki - === Headers === - -main.py headers: -<pre> -""" <your description> -""" -___title___ = "<your_app_name>" -___license___ = "MIT" -___dependencies___ = ["wifi", "http", "ugfx_helper", "sleep"] -___categories___ = ["<see below>"] -___bootstrapped___ = True # Whether or not apps get downloaded on first install. Defaults to "False", mostly likely you won't have to use this at all. -</pre> - -Please use one of these categories: -* System -* Homescreens -* Games -* Sound -* EMF -* Villages -* Phone -* LEDs -* Sensors -* Demo -* Other - -=== Exiting main.py === - -Ensure your apps calls app.restart_to_default() when finished - - - -<pre> -from app import restart_to_default # import at the beginning of your code - - -restart_to_default() # call on exit of main.py -</pre> - 0dkhb3ywb4m9ixzoem4mkqax6bew3hz - - - - TiLDA MK4/Firmware Update - 0 - 63 - - 459 - 458 - 2019-01-19T23:12:57Z - - Jontywareing - 77 - - /* Procedure */ - 459 - wikitext - text/x-wiki - While many of the TiLDA apps can be updated via the Badge Store, the base firmware of the badge must be updated over USB. - -Updating will provide stability and performance improvements, as well as fixing problems with phone calls. - -'''Warning:''' Updating the badge firmware will wipe all apps and settings. Please be sure to have backed up your own code before doing this. - -==What you need== -* A computer running OSX, Linux, or Windows equipped with USB ports -* A micro USB cable to connect your badge -* [[TiLDA_MK4/tilda-tools|TiLDA Tools]] installed -* [http://dfu-util.sourceforge.net/ DFU Util] installed - -==Procedure== -# Connect the Badge to your computer using the USB cable -# Put your Badge into DFU mode (Press the joystick in - it will click, then press the reset button, then let go of the joystick after a second) -# Run <code>tilda-tools firmware-update</code> in a terminal (in the location where you installed TiLDA Tools) -# Follow the onscreen information -# Don't forget to press the reset button once the firmware update was successful! - r8i99wc91li4hxdop487pnqaymcyt9b - - - - TiLDA MK4/Get Started - 0 - 73 - - 453 - 452 - 2018-10-27T00:14:18Z - - Gricey - 76 - - - /* 5. Your first app */ - 453 - wikitext - text/x-wiki - = Get started = - -Hacking your TiLDA Mk4 badge is easy. We've written it down step by step. - -If something goes wrong, the badge can be [[TiLDA_MK4/reset|reset]] to its out-of-the-box state, so do not be concerned about breaking anything. - -== 1. Connect to your computer == -To get started you need to connect your badge to a computer. You can use any MicroUSB cable - the same type that charges most mobile phones nowadays. It doesn't matter whether the battery is plugged in or not, so don't worry about it. - -== 2. Connect to your badge == - -=== Windows === -* Please follow the instruction under the "Windows" section on this page: https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html -* Once you've installed the driver and Putty and you've connected to your badge, press Control+C to stop the main badge app, and then you should be greeted by a line saying "Micropython" - -=== OSX === -* Click the magnifying class in the top right of your screen and type <code>Terminal</code> followed by Enter. A white terminal window should appear. -* type <code>screen /dev/tty.usbmodem*</code> (The * is important, so don't let it out) and hit enter -* hit <code>control+c</code>, if an error is displayed -* You should now be greeted by a line saying "Micropython" - -=== Linux === -* Open a terminal and type <code>screen /dev/xyz</code> (todo: please add the correct path) -* You should now be greeted by a line saying "Micropython" - -=== What to do if this step doesn't work? === -* Press the reset button at the back of your badge and try again -* Have a look at https://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/repl.html for more information - -== 3. Your first line of Micropython == - -* In your terminal (next to the >>>) type <code>print(1 + 1)</code> followed by Enter -* You should see <code>2</code> printed on the screen. Congratulations, you've just written your first line of micropython code! -* You can now close the terminal window (or Putty, if you're on Windows). Note: some serial terminals will not close when the badge is removed or powered off. You should close the serial terminal before plugging the badge back in, otherwise the serial terminal may not reconnect. - -== 4. Download some software you'll need == - -You will be downloading some stuff now. It's probably be best if you create some folder somewhere so you don't end up with files all over your Desktop. - -Note you can copy files across from your computer to the badge, reset the badge and run the files though the menu, however these instructions make things a little easier. - -=== Windows === -* Python: Go to https://www.python.org/downloads/ and download python version 3.x. After the download is finished you can install it. -* Go to https://bootstrap.pypa.io/get-pip.py and save the file into your folder -* Hold shift, right click on the folder on, and click "open command window here" -* Now type <code>python get-pip.py</code> -* After the install was successful please type <code>pip install pyserial pyusb</code> followed by Enter. - -=== OSX / Linux === - -* Python: Open a terminal and type <code>python --version</code>. If you get a version number you're good to go, otherwise go to https://www.python.org/downloads/ and download Python version 3.x. After the download is finished you can install it. -* Go to https://bootstrap.pypa.io/get-pip.py and save the file into your folder -* Use a terminal to go to the folder you created ([http://www.macworld.com/article/2042378/master-the-command-line-navigating-files-and-folders.html this is how you do it]) and type <code>python get-pip.py</code> -* Now type <code>python get-pip.py</code> -* After the install was successful please type <code>pip install pyserial pyusb</code> followed by Enter - -=== Problems === -* If you have problems install python, please use google, there are lots of good explanations out there -* For information about how to install <code>pip</code> have a look here: https://pip.pypa.io/en/stable/installing/ - -== 5. tilda_tools == - -You need to clone our Mk4-Apps repository: https://github.com/emfcamp/Mk4-Apps - -You might find some tricks on how to do this here: https://badge.emfcamp.org/wiki/TiLDA_MK4/Badge_Store_Submissions#Submitting_your_badge_app_to_the_official_badge_store - -There's a python script calle "tilda_tools" in the repository. You can use it to do all sorts of stuff that is a bit complicated to do with the USB mass storage. - -To test it open "adhoc.py" and add the following line at the bottom: -<pre> -ugfx.text(5, 5, "Hello World!", ugfx.RED) -</pre> - -and then run "./tilda_tools run adhoc.py" (or "python tilda_tools run adhoc.py" on Windows) - -Todo: test this on windows - what's the best way of running python scripts there? - -You should now see "Hello World!" on your screen. - -== 5. Your first app == -Let's create an app you can put on your badge. - -* Open the folder you've downloaded from github - You will see other app folders like "badge_store" and "snake". -* Create a folder called "my_app". This is your new app. -* Open a text editor. On Windows you can search for <code>Notepad</code>, on OSX there's one called <code>textedit</code> and if you're on Linux you can probably find one by searching for "edit". -* Copy the following and save it as <code>main.py</code> in your folder: - -<pre> -"""My first app""" - -___title___ = "My app" -___license___ = "MIT" -___dependencies___ = ["ugfx_helper"] -___categories___ = ["Demo"] - -import ugfx_helper, ugfx, tilda, sleep -from app import restart_to_default - -ugfx_helper.init() -ugfx.clear() - -ugfx.text(5, 5, "Hello World", ugfx.RED) -ugfx.fill_circle(100, 100, 30, ugfx.GREEN) -ugfx.fill_circle(200, 100, 30, ugfx.GREEN) -ugfx.area(80, 150, 140, 20, ugfx.GREEN) -ugfx.area(120, 170, 60, 20, ugfx.GREEN) - -while tilda.Buttons.is_pressed(tilda.Buttons.BTN_Menu) is False: - sleep.wfi() # This means sleep for a short while - -ugfx.clear() -restart_to_default() -</pre> - -Now you can run "./tilda_tools app my_app" - Wait a few seconds and you should see your app working on the screen. - -It will now work even when the computer is disconnected. To load it you'll have to open it via the Launcher or use the settings app to make it your default app. - -== 6. Publish your app to the app library == - -Now that you have your own smiley app, why not share it with others? - -See https://badge.emfcamp.org/wiki/TiLDA_MK4/Badge_Store_Submissions for more information - klq1aq7d5vkemqieuzj7t46midhirc3 - - - - TiLDA MK4/modtilda - 0 - 65 - - 306 - 2018-08-29T11:02:29Z - - Davea - 30 - - Created page with "todo: spec this out <pre> >>> import tilda >>> dir(tilda) ['__class__', '__name__', 'Buttons', 'LED', 'Sensors', 'main', 'storage_disable_usb', 'storage_enable_usb'] >>> dir(..." - 306 - wikitext - text/x-wiki - todo: spec this out - -<pre> ->>> import tilda ->>> dir(tilda) -['__class__', '__name__', 'Buttons', 'LED', 'Sensors', 'main', 'storage_disable_usb', 'storage_enable_usb'] ->>> dir(tilda.Buttons) -['__class__', '__name__', 'BTN_0', 'BTN_1', 'BTN_2', 'BTN_3', 'BTN_4', 'BTN_5', 'BTN_6', 'BTN_7', 'BTN_8', 'BTN_9', 'BTN_A', 'BTN_B', 'BTN_Call', 'BTN_End', 'BTN_Hash', 'BTN_Menu', 'BTN_Star', 'JOY_Center', 'JOY_Down', 'JOY_Left', 'JOY_Right', 'JOY_Up', 'disable_all_interrupt', 'disable_interrupt', 'disable_menu_reset', 'enable_interrupt', 'enable_menu_reset', 'get_all_states', 'has_interrupt', 'is_pressed', 'is_triggered'] ->>> dir(tilda.LED) -['__class__', '__name__', 'GREEN', 'RED', 'off', 'on', 'toggle'] ->>> dir(tilda.Sensors) -['__class__', '__name__', 'BAT_ADAPTER_24', 'BAT_DONE_CHARGING', 'BAT_FAST_CHARGING', 'BAT_NOT_CHARGING', 'BAT_NO_INPUT', 'BAT_OTG', 'BAT_PRE_CHARGING', 'BAT_USB_HOST', '_raw_bq', 'get_charge_status', 'get_hdc_humidity', 'get_hdc_temperature', 'get_lux', 'get_tmp_temperature', 'get_vbus_connected', 'sample_rate'] -</pre> - g8n79ps97xzz82o25e9ynd2873lc8ov - - - - TiLDA MK4/Neopix - 0 - 74 - - 395 - 2018-09-01T18:16:38Z - - Sknebel - 64 - - code snippet from leaflet - 395 - wikitext - text/x-wiki - <pre> -from machine import Neopix -n = Neopix() -n.display([0x00ff00,0xff0000]) -</pre> - 8lemwi0c7y9b8cnatgok2oas3zs014d - - - - TiLDA MK4/reset - 0 - 61 - - 343 - 295 - 2018-08-30T16:00:23Z - - Philcrump - 11 - - - Clarify reset process. - 343 - wikitext - text/x-wiki - Should your badge stop working there are these ways to fix it. Please make sure you have a backup of whatever you've been working on, you might lose all the data stored on your badge. - -Todo: Is there an easier way? - -== Factory reset the badge== -Press and hold 'MENU' and then briefly press the reset button on the back. Keep the MENU button held down, then release it when both the green and red LED are on at the same time. Both LEDs should flash for a few times. Wait a few seconds until the blinking has stopped and press reset again. - -After that you should finally get a screen saying "Downloading TiLDA software". It should take less than a minute until the badge functionalities are restored, but you will have to re-install your apps. - -P.S. The micropython documentation on factory resetting is [http://docs.micropython.org/en/latest/pyboard/pyboard/tutorial/reset.html here]. On the TiLDA MK3 the USR button is the MENU button, and the orange LED is actually red. - bgyt7kzf2p0t50le6nlx0r9gyp5uoum - - - - TiLDA MK4/Run Code - 0 - 72 - - 450 - 449 - 2018-09-18T21:59:50Z - - Ms7821 - 4 - - - /* Through the REPL */ - 450 - wikitext - text/x-wiki - -== Through the REPL == -* Todo: Please write how to do that on different operating systems -* todo: how to use a REPL - -'''Important''': once connected to the serial port, you'll only see output the badge sends (usually none). Hit Ctrl+C to exit from the current process and get back the REPL. - -=== Windows/WSL === -==== Identify serial device ==== -The serial device should be a COM port that only shows when you plug the badge in, e.g. COM4: -# Open Computer Management (compmgmt.msc) -# Navigate to Device Manager -# Expand Ports (COM & LPT) - -Alternatively in PowerShell: - - Get-WMIObject Win32_SerialPort | select DeviceID,Description - -==== Connect to identified device ==== -Open PuTTY, enter the COM port found above, e.g. COM4, select Serial, and click Open. - -Alternatively in WSL: - - sudo screen /dev/ttyS{n} - -where {n} is the numeric part of the COM port (e.g. /dev/ttyS4 for COM4). Use Ctrl+A, D to disconnect. - -== Use the "mass storage" app == -* Only works on OSX at present (2nd Sept 2018) -* easy to do -* make sure to safely eject every time -* has a tendency to corrupt the filesystem - link to reset instructions -* hard to debug errors -* todo: add more information - -== Use Mk4-Apps tilda_tools == -* Probably most convenient, but a bit more involved: -* You can use "./tilda_tools run <file.py>" to run code without copying anything, but if you want to make sure you have all your libraries updated use "./tilda_tools app my_app" instead. -* https://badge.emfcamp.org/wiki/TiLDA_MK4/tilda-tools - jpsm9eflse6imroo7pjgykk2fk78swz - - - - TiLDA MK4/sensors - 0 - 67 - - 479 - 362 - 2023-08-22T12:45:06Z - - CircuitCamps - 84 - - - /* Overview */ - 479 - wikitext - text/x-wiki - == Overview == - -The TiLDA MK4 has four sensors, three sharing an [https://www.allaboutcircuits.com/technical-articles/introduction-to-the-i2c-bus/ I2C bus] and one with an analog output: - -* Temperature and Humidity: [http://www.ti.com/product/HDC2080 TI HDC2080] -* Luminance: [http://www.ti.com/product/OPT3001 TI OPT3001] -* Temperature: [http://www.ti.com/product/TMP102 TI TMP102] - the TMP102 has higher precision and extended temperature range with no calibration needed compared to HDC2080 -* Magnetic: [http://www.ti.com/product/DRV5055 TI DRV5055] - -The sensors are physically located on the badge as shown in the picture below. Since these are environmental sensors, the orientation and location of the badge will affect the values returned from the sensors. For example, wearing the badge close to your body will likely raise the temperature readings. - -[[File:Sensor graphic - with fixed transparency-01.png|400px]] -[[File:Sensor graphic - with fixed transparency-02.png|400px]] - -In addition, the battery charger circuit (TI BQ25601), powered via USB, has status available via the I2C bus. - -These sensors are managed by the tilda.Sensors module. This module takes care of initializing the devices and periodically updating readings from them. This makes it easier to use from applications as all the low-level interactions and data formatting are available directly via MicroPython methods. There are more features available in the devices that could be enabled. Currently this would be done by enhancing the C code in the ports/ti directory. In the future, the devices might also be directly programmable via the MicroPython I2C API. - -You can see what's provided by the Sensors module using the standard Python dir() operator: - -<pre> ->>> from tilda import Sensors ->>> dir(Sensors) -['__class__', '__name__', 'BAT_ADAPTER_24', 'BAT_DONE_CHARGING', 'BAT_FAST_CHARGING', 'BAT_NOT_CHARGING', 'BAT_NO_INPUT', 'BAT_OTG', 'BAT_PRE_CHARGING', 'BAT_USB_HOST', '_raw_bq', 'get_charge_status', 'get_hdc_humidity', 'get_hdc_temperature', 'get_lux', 'get_tmp_temperature', 'get_vbus_connected', 'sample_rate'] -</pre> - -Per the usual Python conventions, the all upper-case identifiers are symbolic constant values. The other identifiers are methods that should be semi-obviously apparent in what functions they perform. - -== Temperature and Humidity == - -Two methods are provided for the HDC2080. get_hdc_temperature() returns the current ambient temperature in degrees Centigrade. get_hdc_humidity() returns the relative humidity as a percentage. - -get_tmp_temperature() returns the current ambient temperature in degrees Centigrade from the TMP102 sensor. - -<pre> -from tilda import Sensors - -print("HDC temperature: {} C".format(Sensors.get_hdc_temperature())) -print("TMP temperature: {} C".format(Sensors.get_tmp_temperature())) -print("HDC humidity: {}%".format(Sensors.get_hdc_humidity())) -</pre> - -== Luminance == - -The OPT3001 measures light intensity (luminance) scaled to match the way the human eye perceives light. This is useful for applications controlling lighting so that changes appear more natural to people. - -<pre> -from tilda import Sensors -from time import sleep - -while True: - print("Light intensity: {} lux".format(Sensors.get_lux())) - sleep(1) -</pre> - -Place your hand over the OPT3001 sensor and observe the measured intensity change. - -== Magnetic Flux - Hall Effect == - -The DRV5055 senses magnetic fields (hooray for ElectroMAGNETIC FIELD Camp!). The device provides an analog output that is sampled by the ADC on the MCU. The particular device on the badge has a sensitivity of 12.5mV / mT. Note that the earth's magnetic field is in the range of micro Teslas (uT). Bring a small magnetic close to the sensor and watch the measurements change. - -<pre> -from machine import ADC -from time import sleep_ms - -mag = ADC(ADC.ADC_HALLEFFECT) -while True: - print(mag.convert()) - sleep_ms(200) -</pre> - -== Battery == - -The BQ25601 takes care of charging the LiPo battery when the badge is attached to a USB power source - PC, car, battery. You can monitor the status by using the get_charge_status() and get_vbus_connected() methods. For example, you might want to turn off the display more often when there is no USB power so that the battery lasts longer. - -<pre> -from tilda import Sensors -from machine import Pin - -backlight = Pin(Pin.PWM_LCD_BLIGHT) -if Sensors.get_vbus_connected() != Sensors.BAT_NO_INPUT: - backlight.on() -</pre> - -While there is power supplied via USB, you can monitor the charging status: - -<pre> -from tilda import Sensors - -charging = Sensors.get_charge_status() -if charging == Sensors.BAT_PRE_CHARGING or charging == Sensors.BAT_FAST_CHARGING: - print("Battery is charging") -elif charging == Sensors.BAT_DONE_CHARGING: - print("Battery is full") -elif charging == Sensors.BAT_NOT_CHARGING: - print("Battery is discharging") -</pre> - -== Sample Rate == - -You can change how often the sensors are read using the sample_rate() method. Like other Python APIs, this function is both a "setter" and a "getter". If you call it with no argument, it returns the current sample rate in Hz. If you supply a value, the sample rate is changed. Changing the sample rate can let you see sensor values change more rapidly; conversely, a slower sample rate will update less often but use less energy, making the battery last longer. - -<pre> -from tilda import Sensors - -print("Sensor sample rate: {}".format(Sensors.sample_rate())) -Sensors.sample_rate(2) -</pre> - lpuhk2wg6mze3q81ksrg0m03udd2pon - - - - TiLDA MK4/sim800 - 0 - 66 - - 417 - 363 - 2018-09-03T10:42:01Z - - Mouseboks - 68 - - - 417 - wikitext - text/x-wiki - == Overview == - -The TiLDA MK4 is equipped with an SIM800C module. This is primarily a GSM module for communication with a mobile network. It also has many other features including Bluetooth, a file system and some audio features. - -Below are the features and functions exposed thought this library. - -== Calling == - -=== Call === - -<code>sim800.call(number)</code> - -* number = Number to call. This can be an integer but you will need ti use a string if your number has a "0" prefix - -=== Answer Call === - -<code>sim800.answer()</code> - -=== End/Reject Call === - -<code>sim800.hangup()</code> - -=== Redial === - -<code>sim800.redial()</code> - -== Settings == - -=== Ringer Volume === - -<code>sim800.ringervolume([level])</code> - -* level: If set the volume as a percentage is changed to that value. If not set the volume will not change. - -The current (possibly new) volume level is returned. - -=== Speaker Volume === - -<code>sim800.speakervolume(level)</code> - -* level: If set the volume as a percentage is changed to that value. If not set the volume will not change. - -The current (possibly new) volume level is returned. - -=== Ringtone === - -The SIM800 has 19 terrible ringtones. You can select any of them. My federate is 0 that is also silent. - -<code>sim800.ringtone([alert],[preview])</code> - -* alert: The number of the new ringtone (0-19). -* preview: If True it will play. If False or absent then it will stop. - -The current (possible new) ringtone is returned. The ringtone is always changed regardless of the preview setting. - -=== Ringing === - -<code>sim800.isringing()</code> - -Returns True if ringing. - -The sim800.getstatus() also returns 2 when ringing and machine.Pin(machine.Pin.GPIO_SIM_RI, machine.Pin.IN).value() will show the start of the hardware ringer indicator pin. You an also user a callback (documented below) with the call name of "RING". - -<code>sim800.latestnumber()</code> - -Returns the number of the current caller if ringing. Returns the number of the last caller if not ringing. - -=== Play DTMF === - -<code>sim800.dtmf(number)</code> - -Plays DTMF tones on an active call. - -* number: The number of the tone to play. This can a string of numbers that are played in sequence. Using "," will pause for one second. (int or str) - -== SMS == - -=== List SMS Messages === - -<code>sim800.listsms([stat])</code> - -List available SMS messages. - -* stat: -*: 0 = received unread messages (default) -*: 1 = Received read messages -*: 2 = Stored unsent messages -*: 3 = Stored sent messages -*: 4 = All message - -<code>sim800.newsms()</code> - -Returns True if you have a new (unread) SMS message - -=== Read an SMS Message === - -<code>sim800.readsms(index, leaveunread)</code> - -* index: The index of the message to read. This can be found by calling sim800.listsms(). -* leaveunread: If set to True the message will remain flagged as unread if it was to start with. If False (default) then it will be marked as read. - -If you are looking for a message to process consider setting leaveunread to True until you identify the message is for you or the user will continually find all there messages are read. - -The contents of the message is returned as a string. - -=== Send an SMS Message === - -<code>sim800.sendsms(number, message)</code> - -* number: The number to send the SMS message to. -* message: The message to send as a string. This must be less than 160 8-bit charicters in length. - -=== Delete an SMS Message === - -<code>sim800.deletesms(index)</code> - -index: The index of the message to delete. This can be found by calling sim800.listsms(). - -== File System == - -The SIM800 module has around 90KB of file storage. This can be used to store files to send to or receive from and paired Bluetooth device as well as for audio recordings. - -=== Free Space === - -<code>sim800.fsfree()</code> - -Returns the number of bytes available in the file system. - -=== List Directory === - -<code>sim800.fsls([directory])</code> - -* directory: The directory on the file system relative to root to list. Directories end with a backslash. The root directory is returned if no parameter is given. - -A list of file names is returned. Directories end with a "\". Don't forget to escape this as "\\" in your code. - -=== File Size === - -<code>sim800.fssize(filename)</code> - -* filename: The directory and filename of the file. - -The size of the file in bytes. A size of -1 is returned if the file does not exist. - -=== Create Directory === - -<code>sim800.fsmkdir(directory)</code> - -Creates a directory. - -* directory: The name of the directory to create. - -=== Remove Directory === - -Removes a directory. - -<code>sim800.fsrmdir(directory)</code> - -* directory: The name of the directory to delete. - -=== Create a file === - -<code>sim800.fscreate(filename)</code> - -Creates an empty file. - -* filename: The filename of the file (including directory) to create. - -=== Read From File === - -<code>sim800.fsread(filename)</code> - -Returns the contents of the file. - -* filename: The filename of the file (including directory) to read. - -Note that this can be slow. You may want to use sim800.uartspeed(460800) to speed things up but you are advised to call sim800.uartspeed(0) after to switch back to automatic. - -=== Write To File === - -<code>sim800.fswrite(filename, data, [truncate])</code> - -* filename: The filename of the file (including directory) to read. -* data: The data to write to the file -* truncate: If True the original file emptied first. If False data is appended to the end of the file. Defaults to False. - -Note that this can be slow. You may want to use sim800.uartspeed(460800) to speed things up but you are advised to call sim800.uartspeed(0) after to switch back to automatic. - -=== Delete File === - -<code>sim800.fsrm(filename)</code> - -* filename: The filename of the file to delete. - -=== Rename File === - -<code>sim800.fsmv(from, to)</code> - -Rename a file. - -* from: The old filename. -* To: The new filename. - -== Bluetooth == - -=== Power and Status === - -<code>sim800.btpoweron()</code> - -Turn on Bluetooth. You may also want to call sim800.btvisible(True) to make your badge discoverable. - -<code>sim800.btpoweroff()</code> - -Turn of Bluetooth. - -<code>sim800.btison()</code> - -Returns True if Bluetooth is turned on. - -<code>sim800.btstatus()</code> - -This returns the status of the Bluetooth stack: -:0 = Initial (Not powered on) -:1 = Disactivating -:2 = Activating -:5 = Idle (Normal and waiting) -:6 = Inquiry -:7 = Inquiry Res Ind -:8 = Cancelling inquiry -:9 = Bonding -:11 = Pairing -:12 = Connecting -:14 = Deleting paired device -:15 = Deleting all paired device -:19 = Pairing confirm while passive pairing - -<code>sim800.btrssi(device)</code> - -* device: The device to check. This can be obtained using sim800.btpaired(). - -Returns the signal quality for the device (-127-0) - -=== Settings === - -<code>sim800.btname([name])</code> - -Get and Set the Bluetooth name for your badge. - -* name: The new name of your badge. Omit this to just read the current setting. - -Returns the name (possubly the new name) of the badge. - -<code>sim800.btaddress()</code> - -Returns the Bluetooth address of the badge. - -=== Pairing === - -Before you can use other devices over Bluetooth or they can use you you will first need to pair the device. - -You can pair to most devices. This includes hands free kits for making calls thought your badge. - -<code>sim800.btvisible([visible])</code> - -* visible: If True the badge is visible to other Bluetooth devices. - -<code>sim800.btscan([timeout])</code> - -Scan for other Bluetooth devices. - -* Timeout: Time in milliseconds to search. 10000 to 60000 in increments of 10000. Defaults to 30000. - -Returns a list of device IDs, Names, address, and the rssi of the discovered devices. - -<code>sim800.btpair(device)</code> - -Request a pairing with another device. - -* device: The ID of the device returned from sim800.btscan(). - -You will then need to confirm the pairing with sim800.btpairconfirm(). - -<code>sim800.btpairconfirm([passkey])</code> - -This should only be called once the user has confirmed that the value of sim800.btparingpasscode() is the same number as displayed on the other device. - -* passkey: If your pairing needs a passkey to be entered. This is an old 4 figure pin for compatibility should not be confused with the 6 figure code shown on the other device. - -You can monitor for incoming pairing requests using the callbacks documented below. - -<code>sim800.btpairreject()</code> - -Reject an incoming pairing request. - -<code>sim800.btparingname()</code> - -Returns the name of the device trying to pair with you. - -<code>sim800.btparingpasscode()</code> - -Returns the passcode that the user should check against the screen on the other device. - -<code>sim800.btunpair([device])</code> - -Unpair a Bluetooth device. - -* device: The ID of the device to unpair. This can be found by calling sim800.btpaired(). 0 to unpair everything. - -<code>sim800.btpaired()</code> - -Returns a list of paired devices. - -=== Connecting === - -Once a device is paired you can connect them using a profile to do something useful. please check the SIM800 documentation listed at the bottom to check what is supported by the SIM800C on the MK4 badge. - -<code>sim800.btgetprofiles(device)</code> - -* device: The device to check. This can be obtained using sim800.btpaired(). - -Returns a list of supported profiles a paired device supports. - -<code>sim800.btprofilesupported(device, profile)</code> - -Check if a specific profile is supported by a device. - -* device: The device to check. This can be obtained using sim800.btpaired(). -* profile: The name (string) or ID (integer) of the profile. - -Returns True if it is supported. - -<code>sim800.btconnect(device, profile)</code> - -* device: The device to connect. This can be obtained using sim800.btpaired(). -* profile: The ID (integer) of the profile to connect. - -<code>sim800.btdisconnect(device)</code> - -* device: The profile dosconnect. This can be obtained using sim800.btconnected(). - -<code>sim800.btconnected()</code> - -Returns a list of connected profiles. - -=== Object Push Profile (OPP) === - -This is used to transfer files over Bluetooth. This will transfer files between the internal storage that is limited to about 90K) and other devices. See the File System section for how to transfer data to and from the file system. - -<code>sim800.btopppush(device, filename)</code> - -Send a file to another device. - -* device: The device ID. This can found using sim800.btpaired(). -* filename: The full filename (including directory) if the file to send. - -<code>sim800.btoppaccept()</code> - -Accept an incoming file from a paired device. - -You can get notification of an incoming connection by monitoring "+BTOPPPUSHING:" using the callbacks feature. Files stored in "\\User\\BtReceived". - -<code>sim800.btoppreject()</code> - -Reject a file being offered by another device. - -=== Serial Port Profile (SPP) === - -This allows serial communication with a paired device. At the time of writing this has been written to specification and has not been tested. We hope to have this tested in time but please report any issues to @alistair. - -<code>sim800.btsppwrite(connection, data)</code> - -* connection: The ID of the connected device. -* data: The data to send. - -<code>sim800.btsppread(connection)</code> - -* connection: The ID of the connected device. - -Any received data is returned as a string. - -=== Bluetooth Calling === - -These allow use of phones features over Bluetooth. - -<code>sim800.btcall(number)</code> - -* number: The number to call - -<code>sim800.btanswer()</code> - -Answer an incoming call. - -<code>sim800.bthangup()</code> - -End or reject a call - -<code>sim800.btredial()</code> - -Redial the last number - -<code>sim800.btdtmf(number)</code> - -Send DTMF tones. - -* number: The number to send. - -<code>sim800.btvoicevolume([gain])</code> - -* gain: The volume of the speaker (0-15). Will remain unchanged if omitted. - -Returns the volume if changed or not. - -<code>sim800.btvoicevolume([gain])</code> - -* gain: The gain of the microphone (0-15). Will remain unchanged if omitted. - -Returns the gain if changed or not. - -== Audio == - -=== Play Tone === - -<code>sim800.playtone([freq],[duration],[async])</code> - -* freq: The frequency to play in Hz. -* duration: The duration of the tone in milliseconds. -* async: If True (dafault) it will return instantly and the audio will continue to play for the duration. - -=== Record Audio === - -<code>sim800.startrecording([id],[length])</code> - -* id: The ID of the recording (1-10). Defaults to 1. -* length: The maximum duration of the audio to record in ms. No limit if not set. - -<code>sim800.stoprecording()</code> - -Stop recording audio. - -=== Playback recordings === - - -<code>sim800.startplayback([id], [channel], [level], [repeat])</code> - -* id: The ID of the recording (1-10). Defaults to 1. -* channel: The device to play back on. 0 is the speaker. -* level: Volume to play back at as a percentage. -* repeat: If True the audio will loop. - -<code>sim800.stopplayback()</code> -# Stop playback - -Stop playing back audio. - -=== Manage Recordings === - -Although the recordings show up in the file system you will need to use these functions to manage them. - -<code>sim800.listrecordings()</code> - -Returns an array of the stored recordings. - -<code>sim800.deleterecording([id])</code> - -* id: The ID of the recording (1-10). Defaults to 1. - -== System, Network and Status == - -=== Power === - -The SIM800 module will be powered up when the library is first loaded. You can turn it on and off if you want. - -<code>sim800.ison()</code> - -Returns true if the SIM800 is powered up. - -<code>sim800.poweron([async])</code> - -* async: If True it will return immediately and power on in the background. If False (default) it will wait until it has booted before returning. - -True is returned of the SIM800 if turned on. - -<code>sim800.poweroff([async])</code> - -* async: If True it will return immediately and power on in the background. If False (default) it will wait until it has powered off before returning. - -True is returned of the SIM800 if turned off. - -=== Battery === - -<code>sim800.batterycharging()</code> - -Returns true of the battery is charging. - -<code>sim800.batterycharge()</code> - -Returns the percentage charge of the battery. - -=== Network and SIM Information === - -<code>sim800.getstatus()</code> - -Gets the status of the SIM800. - -Returns: -:0 = Ready -:2 = Unknown: -:3 = Ringing -:4 = Call in progress - -<code>sim800.imei()</code> - -Return the IMEI (International Mobile Equipment Identity) of the badge. - -<code>sim800.imsi()</code> - -Return the IMSI (International mobile subscriber identity) of the SIM. - -<code>sim800.iccid()</code> - -Returns the SIM card's unique serial number. - -<code>sim800.ussd(ussdstring, [timeout])</code> - -Request Unstructured Supplementary Service Data from network (*#xxxxxx#) - -* ussdstring: The command. "*#100#" for example -* timeout: Time to wait in milliseconds. - -<code>sim800.getmynumber()</code> - -Get the telephone number from the network. This only works with some networks and may be formatted text. - -<code>sim800.rssi()</code> - -Return the Received Signal Strength Indication (signal strength) of the current cell communication. - -* 0: -115 dBm -* 1: -111 dBm -* 2...30: -110...-54 dBm -* 31:: -52 dBm -* >99: No signal - -<code>sim800.ber()</code> - -Returns the Bit Error Rate (signal quality) of the current cell communication. Percent value. - -<code>sim800.cellid()</code> - -Returns the Cell ID of the currently connected cell tower. - -<code>sim800.engineeringinfo([neighbour])</code> - -* neighbour: Include full neighbouring cell information if True. - -Returns the engineering information (documented in the docuemtns listed in the advanced section) for the current cell and 6 neighbouring cells. - -=== Network selection === - -<code>sim800.listoperators([available_only])</code> - -* available_only: If True (default) only the networks you can connect to are listed. - -A list of arrays is returned with the following parameters. -: 1=available,2=current,3=forbidden -: Long name -: Short name -: GSMLAI - -<code>sim800.currentoperator(format)</code> - -* format: The format to return the data in. 0=Long name, 1=Short name, 2=GSMLAI - -Returns the current operator. - -<code>sim800.setoperator(mode, [format], [operator]</code> - -This can be used to change the operator. It can also make +COPS calls to the SIM800. - -* mode: 0=automatic,1=Manual selection,2=deregister only,4=try manual then automatic if fails]) -* format: Format of the operator parameter. 0=Long name, 1=Short name, 2=GSMLAI -* operator: The operator to use. - -If you mess things up then sim800.setoperator(0) will reset to defaults. sim800.setoperator(1,3,"23404") will force you on to the EMF Camp network. - -== Callbacks == - -=== Register for a Callback === - -<code>sim800.call(call, function)</code> - -You can register a function that is called when a response is sent by the SIM800. This allows you to detect calls, incoming messages, Bluetooth requests and other advanced responses. - -* call: The response call to be watched for -* function: The function to be called. - -The function must take one string parameter. This parameter contains the the parameters sent from the SIM800. You pass the function by it's name without the training brackets. - -Some example calls are; - -* "RING" - Triggered when an incoming call is detected. -* "+CLIP:" - When caller line identification is received (ie the caller's number). -* "+CMT:" - A new SMS message is received. -* "+DTMF:" - A DTMF tone is detected. -* "+BTPAIRING:" - A Bluetooth pairing request. - -For "RING" the parameter will always be an empty string but your function must accept it. When this is triggered the library the callers number may not be valid and "+CLIP:" should be used instead. - -Take care not to change things the active app will be using such as the string. This call will be in the same thread but may happen in the middle of another function. If odd things start happening with anything on the badge then try disabling your callbacks is a good thing to try. - -=== Deregister from a Callback === - -<code>sim800.deregistercallback(function)</code> - -* function: The function that was used when registering for the callback. - -== Advanced == - -=== UART Speed === - -The communication with the SIM800 autosuggestion by default and we default to 115200 for speed and reliability. You can set the speed to other bauds with the following command. - -<code>sim800.uartspeed(newbaud)</code> - -* newbaud: The speed of the internal communication. Valid values are 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400 and 460800. 0 To revert to default. - -If the badge is rebooted but not power cycled then the speed can get out of sync. Consider switching back to auto when you can to prevent issues related to this. - -=== Custom SIM800 Command Calls === - -<code>sim800.command([command], [response_timeout], [required_response], [custom_endofdata])</code> - -* command: The AT command to send. A full set of of these commands are available in the SIMCom documentation. Links to the most useful ones are below. -* response_timeout: The time to wait for a response in milliseconds. -* required_response: The start of a response we will keep waiting for. If not found in time we will receive a "TIMEOUT" -* custom_endofdata: The start of a response we want for data sent after an "OK" or "ERROR" response. - -This returns an array that should start with an echo of the command sent and normally ends with a response identifying if the call was successful. If a required_response or custom_endofdata is specified then this will be the last line. If such a response has not been received before the timeout a response of "TIMEOUT" is sent. - -As other apps may be monitoring the SIM800 for data relevant to them. Please do not access the UART directly unless you really have to. If you want to receive then use the callback above and call sim800.processbuffer() to process the incoming data. If you really have to then you can access the UART directly via sim800.uart. - -Further details about the AT commands can be found in the following documents. - -* [https://cdn-shop.adafruit.com/datasheets/sim800_series_at_command_manual_v1.01.pdf SIM800 Series AT Command Manual] -* [https://cdn-shop.adafruit.com/product-files/2637/SIM800+Series_Bluetooth_Application_Note_V1.04.pdf SIM800 Series Bluetooth Application Note] -* [https://cdn-shop.adafruit.com/product-files/2637/SIM800+Series_FS_Application+Note_V1.01.pdf SIM800 Series FS Application Note] - -=== Helper Functions === - -There are also some helper functions that you might find useful. - -<code>sim800.sim800.ispositive(response)</code> - -* response: The last line of data returned from sim800.command(). - -Returns True if it was positive such as "OK" or "CONNECTED". - -<code>sim800.isnegative(response)</code> - -* response: The last line of data returned from sim800.command(). - -Returns True if it was negative such as "ERROR" or "NO CARRIER". - -<code>sim800.extractval(parameter, response, [default])</code> - -This looks for the first occurrence of a parameter passed back from the SIM800. - -The value of the parameter is returned as a string, or the default if it is not found. - -* parameter: The parameter you are looking for. "+GCAP:" for example. -* response: The response from sim800.command() -* default: The value to return if the parameter is not found. Defaults to an empty string. - -<code>sim800.extractvals(parameter, response)</code> - -This looks for the occurrences of a parameter passed back from the SIM800. - -An array of values of the parameters are returned. - -* parameter: The parameter you are looking for. "+CENG:" for example. -* response: The response from sim800.command() - -=== Firmware === - -<code>sim800.getfirmwarever()</code> - -Returns the firmware version installed on the SIM800. If it does not end with "_BT" then your Bluetooth will not work. Drop in to the badge tent or contact the badge team online for help. - tgayi5r55z7t5g4i3lwto6rc8h0mdjz - - - - TiLDA MK4/sim800/Reverse engineering - 0 - 68 - - 354 - 2018-08-30T21:14:42Z - - Renze - 58 - - Add page about reverse engineering efforts - 354 - wikitext - text/x-wiki - This page represents an effort to find out more about the inner workings of the SIM800 module found on the TiLDA MK4 badge. - -Feel free to add your own research, but please do not remove content added by other people, even if you determined the information to be false. -Instead you could add text explaining why the existing content was wrong. - -== Usefull links == -Page with firmware, update tool and instructions: https://www.raviyp.com/embedded/214-learn-how-to-update-the-firmware-of-your-sim800-modules -Information about Mediatek chipsets: https://www.bunniestudios.com/blog/?p=4297 -Information on Mediatek file formats: https://wiki.postmarketos.org/wiki/Mediatek#Image_format - -== Current state of research == -Based on the flashing utility and firmware file provided on the raviyp website the SIM800 module probably contains a Mediatek dumb-phone chipset. Bunny did some research on those already, which can be found on his [[https://www.bunniestudios.com/blog/?p=4297|blog]]. - -== To-do list == - - Removing the lid from a SIM800 module and taking photos of the insides - - Figuring out exactly which (Mediatek) chip is inside the SIM800 - - Find a way to replace the built-in ringtones - - ??? - - Profit! - qfw4hgocpekf9gna7de7dc2b8jj844u - - - - TiLDA MK4/tilda-tools - 0 - 64 - - 443 - 415 - 2018-09-14T13:33:02Z - - GavinAtkinson - 73 - - 443 - wikitext - text/x-wiki - ''tilda_tools'' is a toolchain for working with the micropython environment on the badge. - -== Dependencies == - -* Python 3 -* pyserial -* dfu-util (only needed for reflashing firmware) - -== Installation == - -* Clone the Mk4-Apps repo from https://github.com/emfcamp/Mk4-Apps/ (see [https://help.github.com/articles/cloning-a-repository/ Cloning a repository] for help). Alternatively you can download a ZIP file from the repository page. - -* Open a terminal in the Mk4-Apps/ directory. ''tilda_tools'' is in the root of this directory. - -* Windows Users - you will need to install Pyserial to get some commands working - Instructions [https://badge.emfcamp.org/wiki/TiLDA_MK4/Get_Started here] - -== tilda-tools == - -<pre>tilda_tools <options></pre> - -Windows users, create/update a tilda_tools.bat windows batch file, containing the following: -<pre> -@echo off -python %CD%/.development\tilda_tools.py %* -</pre> -This batch file massively simplifies previous versions, but some things may still not work, depending upon whether you can get the driver to work. - -<pre> -Parameters ------------------ - --d --device : serial interface (default: auto) --s --storage : path to flash storage - -Usage ------------------------------------- - -Reboot badge -$ tilda_tools reset - -Soft reboot badge and start specific app -$ tilda_tools reset --boot my_app - -Update files on the badge to match the current local version, restarts afterwards -$ tilda_tools sync - -Notes for tilda_tools sync: - -1. You will probably want to delete the apps you don't want before doing this. There are a lot of apps now and they will take up valuable file space and may well use it all up, crashing the badge. -2. You may want to delete bootstrap.py otherwise, when you reset the badge, it will ask you to connect to wifi and then it will download from the server. i.e. it's like doing a factory reset. -3. Consider syncing a single app - -Update files in folder(s) to match current local version -$ tilda_tools sync my_game shared -$ tilda_tools sync <pattern1> <pattern2> ... - -Sync (as above), but execute my_app after reboot -$ tilda_tools sync --boot my_app [<other sync parameter>] - -Sync (as above), but execute a single file afterwards without copying it to the badge -$ tilda_tools sync --run some_other_file.py - -Sync a given app and execute it -$ tilda_tools app home_default - -Executes a single file on the badge without copying anything (Using pyboard.py) -$ tilda_tools run my_app/main.py - -Runs local validation (doesn't require a badge, but doesn't run unit tests) -$ tilda_tools validate - -Runs local validation and badge-side tests -$ tilda_tools test - -Update firmware on badge (warning, this will delete all settings etc. stored on the badge!) -$ tilda_tools firmware-update - -Setup wifi.json to be copied to the badge on every sync -$ tilda_tools wifi -</pre> - dr78d19upaebe5rryj77yfak8fw0rdj - - - - TiLDA MK4/ugfx - 0 - 60 - - 451 - 442 - 2018-09-25T16:47:36Z - - Jediminer543 - 75 - - ImageBox is infact Imagebox on the api because reasons - 451 - wikitext - text/x-wiki - The badge makes use of [http://ugfx.io uGFX] for providing drawing functions on the LCD. Most of this functionality is available through the micropython interface, and you may wish to browse the [https://wiki.ugfx.io/index.php/Main_Page uGFX documentation] for more details. - -To discover exactly which ugfx calls are available in micropython, see https://github.com/emfcamp/micropython/blob/tilda-master/stmhal/modugfx.c - -== Basic usage == - -uGFX is comprised of 'widgets,' such as buttons and labels, and 'containers' which are used to group widgets. - -To create a button on the screen, use <code>ugfx.Button(x,y,width,height,text)</code>, and a button will be drawn on the screen. - -As well as widgets, there are 'primitives' such as drawing circles and lines, which can be drawn anywhere on the screen or in a container. -For example <code>ugfx.circle(50,50,20,ugfx.RED)</code> will draw a circle. - - - -== Detailed documentation == - -Note. all co-ordinates are from the top left (battery symbol) corner. All widgets are created from the "ugfx" package, eg: ugfx.Contailer(). - -=== Colour format === - -Internally, ugfx uses 565 format (5 bits for red and blue, 6 for green). Preset colours are available, for example '''ugfx.RED''', '''ugfx.ORANGE''', etc. To convert from 24 bit RGB format, use '''ugfx.html_color(0xRRGGBB)''' to return the 16 bit 565 format. - -=== Styles and Fonts === -Use <code>ugfx.set_default_font(...)</code> to change the font. The font options are: -* ''ugfx.FONT_SMALL'' -* ''ugfx.FONT_MEDIUM'' -* ''ugfx.FONT_MEDIUM_BOLD'' -* ''ugfx.FONT_TITLE'' -* ''ugfx.FONT_NAME''. -Note that widgets use the font which was default when they were created, while the ''container.text()'' primitive uses the font that was default when the container was created - -=== Containers === - - .Container(x, y, width, height {,style}) # the style is optional - -Containers can be used to group widgets together. They can also perform primitive drawing functions. When drawing widgets or primitives, the coordinates are relative to the top left corner of the container. - -Containers can be shown or hidden, and all the widgets will be redrawn (primitives are not widgets and are not redrawn). Containers can also be placed on top of other widgets. When the top container is hidden, the widgets below will be redrawn. - -Upon creation a style can be passed to a container, which will then be used by default by widgets created as part of that container. If no style is specified at creation, the current default style will be used. - -The following example shows how to create a container, add an object and show it. -<pre> -c = ugfx.Container(100,100,200,100) -b = ugfx.Button(10, 10, 40, 30, "OK", parent=c) -c.show() # the container will not be shown until this point -c.fill_circle(5,5,5,ugfx.RED) #draws a small red circle. Note this has to be done after .show() -</pre> - -=== Primitives === -All primitives can be drawn anywhere on the screen with, for example <code>ugfx.circle(..)</code>, or anywhere within a container, with <code>c=ugfx.Container(30,30,100,100); c.circle(..)</code> - -Note: The container must be shown ''before'' you can draw primitives in it. When hiding the container, all drawings are lost! - -==== Clear ==== - -<code>.clear(colour = ugfx.WHITE)</code> - -clears the screen to the specified colour. Warning, this is slow! - -==== Lines ==== -<code>.line(<x1>, <y1>, <x2>, <y2>, <colour>)</code> - -<code>.thickline(<x1>, <y1>, <x2>, <y2>, <colour>, <width>, <round>)</code> - -Draws a line from ''x1,y1'' to ''x2,y2'' using ''colour''. Thickline will draw a line or arbitrary width, with the option of rounded corners - -eg. ''ugfx.thickline(0,0,100,170,ugfx.YELLOW,7,0)'' - -==== Circle ==== -<code>.circle(x, y, radius, colour)</code> - -<code>.fill_circle(x, y, radius, colour)</code> - -Draws a circle at ''x,y'' of <radius> using ''colour'', either with a 1 pixel border or filling the area. - -eg. ''ugfx.circle(180,150,40,ugfx.RED)'' - -==== Arc ==== -<code>.arc(x, y, r, angle1, angle2, colour)</code> - -<code>.fill_arc(x, y, r, angle1, angle2, colour)</code> - -Similar to the circle functions, however two angle parameters specify between which two angles drawing occurs - -==== Ellipse ==== -<code>.ellipse(x, y, a, b, colour)</code> - -<code>.fill_ellipse(x, y, a, b, colour)</code> - -Draws an ellipse at ''x,y'' of ''a'' width and ''b'' height using ''colour'', either with a 1 pixel border or filling the area. - -==== Rectangles ==== -<code> .box(1, y, a, b, colour) </code> - -<code> .area(x, y, a, b, colour)</code> - -Draws a rectangle or filled rectangle at ''x,y'' of ''a'' width and ''b'' height using ''colour''. - -==== Polygon ==== -<code> .polygon(x, y, array, colour) </code> - -<code> .fill_polygon(x, y, array, colour) </code> - -Draws or fills a polygon starting at ''x,y'' using ''colour''. ''Array'' is an array of coordinates that specifies the corners. - -eg. ''ugfx.polygon(0,0, [ [0,20],[20,20],[20,0]], ugfx.RED)'' - -==== Text ==== -<code>.text(x, y, text, colour) </code> - -Draws a text string ''text'' at ''x,y'' in ''colour''. -Note that a ugfx.text(..) call will take the default font, while container.text(..) will take the containers font. - -eg. ''ugfx.text(40,40,"My name is...",ugfx.BLUE)'' - -==== Other ==== -<code>.width()</code> - -<code>.height()</code> - -Gets the height or width of the screen ''ugfx.width()'' or container object ''c.width()'' - -=== Widgets === - -Widgets can be drawn anywhere on the screen, or within a container. The widgets take the optional parameter ''parent='' to set the parent container. Widgets can have their style set on creation, otherwise will inherit - -Widgets also accept input from the buttons. For example, the 'A' button can be 'attached' to an on-screen button, such that pressing the button on the badge causes the on-screen button to be redrawn in a depressed state. - -==== Common Widget methods ==== - -<code>.text([text])</code> - -Gets or sets the text displayed by the widget. - -<code>.visible([show])</code> - -Gets or sets the visibility of the badge. ''b.visible(0)'' will hide, and ''b.visible(1)'' will show. - -<code>.attach_input(button, function)</code> - -Attaches a physical button to a widget, so that the user can cause the widget to redraw, for example to scroll or become depressed. - -The input ''button'' specifies which button, with the options ugfx.BTN_A, ugfx.BTN_B, ugfx.BTN_MENU, ugfx.JOY_UP, ugfx.JOY_DOWN, ugfx.JOY_LEFT, ugfx.JOY_RIGHT. - -The input ''function'' specifies what the button actually does. For example, the list has three different functions: scroll up, scroll down, and select. Note that some widgets by default attach the joystick to the relevant functions. - -<code>.detach_input(function)</code> - -Detaches an input. See above for more details. - -<code>.destroy()</code> - -Frees up all the resources assoicated with the object. While the micropython garbage collector will clear any old objects, the graphics library also has its own memory area, which can become full if objects are not destroyed after they are needed. - -<code>.set_focus()</code> - -Gives focus to the widget instance. Normally this will draw a box around the widget, the colour is specified by the style. - -==== Button ==== - -<code> b=ugfx.Button(x, y, w, h, text, *, parent=None, trigger=None, shape=ugfx.Button.RECT, style=None) </code> (note: parameters after '*' are optional) - -Draws a button at ''x,y'' having width ''a'' and height ''b''. The option 'trigger' specifics which physical switch (if any) causes the display to be redrawn. The shape options are ''ugfx.Button.RECT'', ''ugfx.Button.ROUNDED'', ''ugfx.Button.ELLIPSE'', ''ugfx.Button.ARROW_UP'', ''ugfx.Button.ARROW_DOWN'', ''ugfx.Button.ARROW_LEFT', ''ugfx.Button.ARROW_RIGHT''. - -==== Textbox ==== -<code> ugfx.Textbox(x, y, w, h, *, text=None, parent=None, maxlen=255})</code> - -Draws a text edit-box which can take input from the on-screen keyboard. Will automatically accept key-presses from the keyboard, which will edit the text. The textbox needs to have focus using .set_focus() for it to receive the key-presses. - -==== Checkbox ==== - -<code>.Checkbox((x, y, w, h, text=None, parent=None, trigger=None, style=None)</code> - -<code>.checked()</code> - -Get or set the checked state - - -==== Label ==== - -<code> ugfx.Label(x, y, w, h, text, *, parent=None, style=None, justification=None)</code> - -A label displays text. Unlike the primitive text, this Label supports different justifications, wordwrap and changing text. The different justification options are ''ugfx.Label.LEFT'', ''ugfx.Label.RIGHT'', ''ugfx.Label.CENTER'', ''ugfx.Label.LEFTTOP'', ''ugfx.Label.RIGHTTOP'' and ''ugfx.Label.CENTERTOP''. - -==== List ==== - -<code>ugfx.List(x, y, w, h, *, parent=None, up=ugfx.JOY_UP, down=ugfx.JOY_DOWN, style=None)</code> - -<code>.enable_draw()</code> - -<code>.disable_draw()</code> - -<code>.add_item(text)</code> - -<code>.assign_image(index, image)</code> - -<code>.remove_item(index)</code> - -<code>.selected_text()</code> - -<code>.selected_index()</code> - -<code>.count()</code> - -==== Graph ==== - -<code>ugfx.Graph(x, y, w, h, origin_x, origin_y)</code> - -<code>.show()</code> - -<code>.hide()</code> - -<code>.set_arrows(ugfx.Graph.ARROWS_X_POS | ugfx.Graph.ARROWS_Y_POS)</code> - -Set which axes have arrows and in which direction. In this example arrows are set for the x and y positive directions, with the following options available: ARROWS_X_POS, ARROWS_Y_POS, ARROWS_X_NEG, ARROWS_Y_NEG - - -<code>.plot( point(s)_x, point(s)_y, {new_series} )</code> - -Plot either an array, or a point. Optional second parameter specifies whether to start a new series or join onto previous. - - -<code>.appearance( thing_to_change, shape, size, colour, {spacing} )</code> - -Changes the style of either points, lines, axis or grids. Each parameter is used as follows: - -'thing_to_change' - select what aspect to change, the options are {STYLE_POINT, STYLE_LINE, STYLE_XAXIS, STYLE_YAXIS, STYLE_XGRID, STYLE_YGRID} - -'shape' - selects the shape of the thing to change, where the options depend on what you are changing. -The options for points is: {POINT_NONE, POINT_DOT, POINT_SQUARE, POINT_CIRCLE} -The options for line/axis/grid are: {LINE_NONE, LINE_SOLID, LINE_DOT, LINE_DASH} - -'size' - number of pixels wide of the thing to change - -'colour' - use UGFX.Red, UGFX.Orange,... or UGFX.html_color(0xRRGGBB) to ensure the right format - -'spacing' - only valid for grid - -See the [https://github.com/emfcamp/Mk3-Firmware/blob/master/apps/logger/main.py BARMS logger app] for an example - -==== Imagebox ==== - -<code>.Imagebox(x, y, w, h, filename, *, cache=0, parent=None, style=None)</code> - -This displays an image box. This will automatically animate a passed gif - -==== Keyboard ==== - -<code>.Keyboard(x, y, w, h, parent=None)</code> - -=== Styles === -<pre> -s=ugfx.Style() # create a style based on the current default style - -s.set_enabled([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is enabled -s.set_pressed([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is pressed -s.set_disabled([text_colour, edge_colour, fill_colour, progress_colour]) # sets the style for when something is disabled - -s.set_focus(colour) # sets the colour used for focus -s.set_background(colour) # sets the background colour for the style - -ugfx.set_default_style(s) # use this style from now on - -b=ugfx.Button(0,0,40,30,"OK", style=s) # use the style for this button - -</pre> - -== Tips and tricks == - -=== Tearing === - -When writing large areas of the screen, a 'tearing' [https://en.wikipedia.org/wiki/Screen_tearing] effect may be observed. - -The screen module is comprised of a large memory, with one memory location to store the RGB data for each pixel. The LCD driver continuously updates the LCD pixels, by reading the memory in a sequential, line-by-line manner, and updating the LCD with the data from the memory. This 'read line-pointer' moves from the top to the bottom of the screen (when viewed in portrait), at about 70Hz (the refresh rate of the screen) - -This large memory as part of the screen means it can be driven by a microcontroller which may have a considerably smaller memory. The microcontroller therefore only needs to update the memory when it whats the content to change. - -Consider the scenario where the microcontroller wants to set the screen from one colour to another. The microcontroller needs to update the entire memory (320x240x2 = 153kB) with the new colour. At the same time the 'read line-pointer' is reading the same memory to update the LCD. In this case, tearing occurs if the 'read line-pointer' reads the top half of the memory containing the new colour, but then catches up with microcontroller writing to the memory, then the 'read line-pointer' starts reading the old colour in the bottom half of the memory. - -To avoid tearing the 'read line-pointer' should not cross the region the microcontroller is updating. Since the microcontroller writes to the screen slightly slower than the LCD reads it, providing the microntroller starts writes to the top of the memory just after the LCD starts reading from the top, the read and write pointers will not overlap, and tearing will not occur. To sync the microcontroller with the LCD 'read line-pointer,' there is a vsync/tear output (connected to pin named 'TEAR') which is pulled high when the 'read line-pointer' reaches a given line (default is line 0). This can be turned on and off with '''ugfx.enable_tear()''' and '''ugfx.disable_tear()'''. To change the line at which the tear output is generated, use '''ugfx.set_tear_line(0..319)'''. - -Example code: - - ugfx.enable_tear() - tear = pyb.Pin("TEAR", pyb.Pin.IN) - - def vsync(): - while tear.value() == 0: - pass - while tear.value(): - pass - -=== Reducing power consumption === -Use the following to dim the backlight, which uses about 80mA at full brightness -<pre> -ugfx.backlight(b) # sets the backlight. Range is 0-100 -b = ugfx.backlight() # reads the current backlight -</pre> - -== Top-Level calls == - -<code>.power_mode(<mode>)</code> - -''mode'' can be any of: ugfx.POWER_ON, ugfx.POWER_OFF, ugfx.POWER_DEEP_SLEEP, ugfx.POWER_SLEEP - -<code>.orientation(deg)</code> - -Rotate the display by number of degrees, eg 180 for upside-down. - -Calling with no args returns the current value - -<code>.display_image(x, y, '/path/to/image', orientation)</code> -<code>.display_image(x, y, img_obj, orientation)</code> - -Display an image from a file of a supported type, or a previously opened image object, on screen at the x,y co-ordinates. Optionally change its orientation. - -<code>.write_command(0x35,0)</code> - -Low-level command to write to a data register directly. - -<code>.poll()</code> - -Yield to ensure the screen is redrawn when waiting on user input - -<code>.ball_demo()</code> - -Ball Demo! - -<code>.get_pixel(x, y)</code> - -Returns the colour of the pixel at x,y - -<code>.Image(filename, cacheme)</code> - -Creates and returns (or loads from cache) a ugfx image object from the image in the filename. - 029irwzclpoggzps28wnci2t1qryjio - - - - TiLDA MKe - 0 - 3 - - 466 - 465 - 2021-05-26T08:18:09Z - - Thinkl33t - 2 - - 466 - wikitext - text/x-wiki - [[File:IMG_0474.jpg|500px|right|thumb|Front]] -[[File:Badge_Front.png|right|thumb|Front]] - -[http://en.wikipedia.org/wiki/E_(mathematical_constant) Why MKe?] - -=EMF 2014 Badge= -The main aim of the 2014 badge is to give camp attendees an interesting bit of hardware to play with during the camp and experiment with afterwards. We designed an Arduino compatible platform to allow easy reuse and access, and have published all code and design files. - -[http://blog.emfcamp.org/post/94157161753/announcing-tilda-mke-the-incredible-emf-2014-camp Blog post launching the badge] - -==Battery Warning== -A very last minute battery (and connector) change on the badge due to a supplier problem meant two issues arose with the badge during EMF: - -* '''Always make sure to plug your battery in the right way round!''' The new battery connector allows you to connect it backwards. We did our best to mitigate this, but connecting it incorrectly will destroy the power management controller and prevent the badge from charging or running from the battery. It will still function perfectly using USB power. "Red" and "Black" are written next to the connector - please make sure to plug it in correctly. - -* '''Be careful not to short the battery connector wires!''' The new battery connector slightly exposes the wires when the battery is plugged in. If a metal object shorts the two wires, it can result in extreme battery damage. If we'd known this was such an issue before the event we would have applied protective material to it - we suggest covering the exposed connector in tape, sugru, blu-tack, or some other insulating material. Alternatively, simply unplug the battery when your badge is not in use! - -==My badge is broken!== -Due to the aforementioned supplier issues it is possible that you may have received a faulty badge, or it may have been damaged by connecting the battery backwards. If you badge will not turn on when it has been plugged in with a MicroUSB cable (and the power switch on the back is set to "USB"), or something else seems wrong with it, please email [mailto:badge@emfcamp.org badge@emfcamp.org] and we'll try to fix or replace your badge. - -=The Hardware= -The badge has a plethora of hardware built in for you to play with, everything from accelerometers and gyroscopes to hidden ethernet headers! Breaking it all down is too much detail for this document, however we'll call out some things we built in that you might want to play with. - -Remember the badge is Arduino Due compatible, and we broke out nearly all the features of the ARM chip so you can access them. [http://arduino.cc/en/Main/ArduinoBoardDue Anything the Due can do], the TiLDA can do! - -==Interesting things to play with== -Most of the interesting things are on the back of the badge. They're clearly marked in white. [https://wiki.emfcamp.org/w/images/b/bd/Badge_Back.png This diagram of the back] should allow you to locate them. Some of the following require extra parts to be added to your badge. - -* Full Arduino R3 shield compatible pins (Requires soldering the headers on the back of the badge) -* Pins either side of the lanyard holes for conductive thread (D19, D18, GND, 3V3) -* Infrared transmitter on the front (Pin shortcut IR_TX_PWM) -* Infrared receiver on the front (Pin shortcut IR_RX, Part Vishay TSOP75238TT available from digikey and Farnell ) -* Piezo buzzer (Pin shortcut PIEZO or PIEZO_PWM) -* On-board ethernet (not available on the Due) - requires breakout module (eBay: Elechouse Taijiuino Ethernet PHY DM9161 Module) -* [http://www.invensense.com/mems/gyro/mpu6050.html MPU-6050] 3-axis Accelerometer and 3-axis gyro (IMUTask.cpp and the MPU6050 library) -* 128x64 pixel backlit LCD display (JHD12864, see [https://github.com/emfcamp/Mk2-Documentation/tree/master/LCD%20JHD12864 here for docs]) -* [http://shop.ciseco.co.uk/srf-wireless-rf-radio-surface-mount/ Ciseco SRF Radio] -* 1 megabit flash module (Part S25FL216K0PMFI011) -* 2x RGB LEDs on the front - -Some features are not mentioned here, or optional extras. They can be found in the [[TiLDA_MKe/Full_Specification]] - -=The Software= - -==Basic post-event features== -We made sure that the badge has a few features to play with once the event is over. More will be added over time as attendees submit changes to us. - -[[File:Badge_Back.png|right|thumb|Back]] -* Torch mode - Press the light button next to the screen. It will only light up fully if it's hung upside down to avoid blinding -* Snake -* Tetris - -But of course the point of the badge is to modify it and use it for other interesting things! The following sections describe how to update the firmware on the badge, how to use it as a simple arduino, and how to write your own code for the main badge firmware. - -==Getting help== -The EMF 2014 badge is a complex piece of hardware and software, however remember that you can just treat it as an Arduino if you find it all too daunting. - -If you get stuck and need advice, join us in #emfcamp-badge on [https://libera.chat/ Libera IRC] to ask for advice, or if you're really stuck you can email us on [mailto:badge@emfcamp.org badge@emfcamp.org]. - -==How to update the badge software== -The badge software has been substantially updated since EMF, fixing bugs and removing features that will no longer work now you're away from our radio network. You should update your badge before starting to play with it any further. If you've never used an Arduino before this might be tricky - ask an Arduino-literate friend to help you, or drop by your nearest [http://hackspace.org.uk hackspace] and ask for advice. - -The badge is Arduino Due compatible, so [http://arduino.cc/en/Guide/ArduinoDue some of their instructions may help you if you have problems]. - -===Set up your environment=== -* Plug your badge into your computer via a MicroUSB cable. Make sure the power switch on the back is set to "USB". -* Download the newest version of the Arduino IDE from http://arduino.cc/en/main/software -* Download the TiLDA firmware code from https://github.com/emfcamp/Mk2-Firmware -* Start the Arduino IDE. -* Now you have to change the sketchbook-folder to be the folder you just cloned or downloaded. To do this use File -> Preferences -> “Set Sketchbook location”. On MacOS, this is Arduino -> Preferences. -* Restart the Arduino IDE. -* Open sketch “EMF2014”. -* Set Tools -> Board to MKe v0.333 (RTOS Core). -* Set Tools -> Port to correct port for the Arduino -** On MacOS this is will start /dev/tty.usbmodem with 4 digits, and change for each port -** On Linux this is usually /dev/ttyACM0 but may be a higher number if you have other USB Serial devices -* Hit the upload button -* Wait -* Your badge should now be running the latest TiLDA firmware! - -==Programming the badge as an Arduino== -The badge is completely Arduino Due compatible, simply set the board type to "MKe v0.333(Arduino Core)" upload normal Arduino code and the badge will function. - -If you program the badge with simple Arduino code, you can always revert to the official firmware. Simply change the sketch to "EMF2014", and set the board type to "MKe v0.333 (RTOS Core)") and upload. - -===blink.ino=== -Here is a tweaked version of the standard blink sketch that will flash the RX and TX LEDs - -<pre> - void setup() { - pinMode(PIN_LED_TX, OUTPUT); - pinMode(PIN_LED_RX, OUTPUT); - } - - void loop() { - digitalWrite(PIN_LED_TX, HIGH); - digitalWrite(PIN_LED_RX, LOW); - delay(1000); - digitalWrite(PIN_LED_TX, LOW); - digitalWrite(PIN_LED_RX, HIGH); - delay(1000); - } -</pre> - -#TODO ADD LINK TO PIN MAPPING NAMES/DEFINITIONS - -===Writing to the Screen=== -#TODO - -===Reading from the Accelerometer=== -#TODO - -===Reading the Battery Voltage=== -#TODO - -===Controlling the LEDs=== -#TODO - -===Reading Button & Joystick Input=== -#TODO - -===Buzzer?=== -#TODO - -===Using the Radio to Send and Receive Data=== -#TODO - -===Arduino Gotchas=== -* Most Arduino code out there use Serial not SerialUSB. On MKe Serial is wired to the SRF radio. When using example code do a find and replace for Serial/SerialUSB this will redirect the Serial traffic of the USB port -* If you want to send data over the Radio you need to wake it and enable it first, set SRF_SLEEP to LOW using the following two lines of code <code>pinMode(SRF_SLEEP, OUTPUT); digitalWrite(SRF_SLEEP, LOW);</code> - -==Programming the badge in FreeRTOS== -[[TiLDA_MKe/FreeRTOS|See this page for information on howto program your badge using FreeRTOS]] - -==Contribute== -Send us a pull request via [https://github.com/emfcamp/Mk2-Firmware GitHub] - We’ll do our best to review and merge the good ones so others can use them. - -=Cool Hacks!= -==3d printable & laser-cuttable badge case== -3d print-able and laser-able case files [http://www.thingiverse.com/thing:436815 here] - -==Making the badge Arduino shield compatible== -[[File:Sheild_Headers.JPG|500px|right|thumb|Sheild Headers]] -To make the badge Arduino shield compatible you'll need to solder simple strips of header pins onto the back of the badge. -You need the following headers -{| class="wikitable" -|- -! Qty !! Type !! Use !! Rapid part -|- -| 1 || 2x03 Male || SPI || -|- -| 2 || 1x08 Female || Power, Analog pins || -|- -| 2 || 1x10 Female || Digital pins || -|- -| 1 || 2x08 Male || Ethernet || -|} -The picture to the right shows the placement. - -= Source = - -All the source code and designs are on openly available on Github: - -* [https://github.com/emfcamp/Mk2-Hardware Hardware] - the full board design -* [https://github.com/emfcamp/Mk2-Documentation Documentation] - a dump of relevant parts datasheets -* [https://github.com/emfcamp/Mk2-Firmware Firmware] - source code for the badge software -* [https://github.com/emfcamp/Mk2-Software Software] - server-side software for the network - -If you want to help, point your IRC client to #emfcamp-badge on [https://libera.chat/ Libera IRC]. - -[[Category: Badges]] - p0lbsn53ui47gyfv1kiyi6mtemcalac - - - - TiLDA MKe/FreeRTOS - 0 - 8 - - 17 - 2015-05-01T15:54:34Z - - Thinkl33t - 2 - - Created page with "=Programming the badge in FreeRTOS= ==Your first “Hello world” app== There’s a “HelloWorldApp.cpp” file in which you can play around. In order for it to show up on t..." - 17 - wikitext - text/x-wiki - =Programming the badge in FreeRTOS= -==Your first “Hello world” app== -There’s a “HelloWorldApp.cpp” file in which you can play around. In order for it to show up on the Homescreen you have to uncomment line 51 in AppManager.cpp and flash the changed code to the badge. Great app pull requests are appreciated! - -If you are still using the Arduino IDE at this point, note that it will not let you edit the .cpp and .h files that are needed to create Apps for the badge. To force the IDE to re-compile/re-read any files you've edited using an external editor, make sure to go to the File -> Preferences dialog box, and check the "Use external editor" checkbox. - -==Why are things so different from standard Arduino code?== -We’re using a library called FreeRTOS that allows us to multitask - something that’s normally not possible with standard Arduino code. This allows us to run multiple tasks at the same time. FreeRTOS uses preemptive scheduling to switch between the task. Due to this we have to be very careful about how we do some things. For example we can’t just define interrupts for buttons in every task (imagine the mess!) or write to the serial port directly (your task might stop in the middle of the message). - -We’ve also spent quite a lot of time to make the built-in components as easy to use as possible without having every task to write lots of boilerplate code. If you feel like using the build-in components on the badge, chances are we already wrote a wrapper for them that is already used by one of the other tasks. - -Have a look at the “Documentation” section in this document for a full list of API functions. You will avoid a lot of headaches if you stick to those. - -== Code structure == -* FreeRTOS has the concept of “Tasks” which work like threads. We’ve wrappered them in a class called “Task” (for background stuff) and “Apps” (for foreground, one-at-a-time things) -* Everything needs to be in the main EMF2014 folder. Subfolders are not allowed. This is an Arduino IDE restriction :( - -==Debugging and Gotchas== -* The USB serial is set up to 115200 baud. There are lots of terminals that can connect to them. See below for how to enable the debug logging. -* If you can’t revive a badge, or only get the two red programming LEDs when you plug it, in, do a full erase (see below) -* Avoid busy waiting, use FreeRTOS queues and Tilda::delay() instead -* Don’t use low level functions like interrupts or serial ports directly unless you really, really know how FreeRTOS will handle them. For general logging you can use Tilda::log() -* If sending code to the badge using the Arduino IDE "Upload" button fails, even though the /dev/ttyACM0 (linux com port) is there, just retry, twice if neccessary. - -==Full erase== -This is the failsafe process if your badge won't show up over USB. - -# Unplug the badge -# Connect the Erase pins on the back together (two holes down the left hand side next to the battery and under the blue wireless module). You can use a jumper, jump wire, or the leg of a resistor for this. -# Turn the badge back on with the switch or plug it back in -# Press the Reset button on the front (bottom centre) and release -# Wait 15 seconds -# Unplug the badge or turn it off - -When you plug the badge back into a computer it will come back up in programming mode, with a different serial port to the usual one. Open the EMF 2014 sketch in the Arduino IDE, select the Tilda v0.333 (RTOS) programmer, and find the new serial port. The IDE console should show something like this: - - Sketch uses 118,748 bytes (22%) of program storage space. Maximum is 524,288 bytes. - Erase flash - Write 127668 bytes to flash - - [ ] 0% (0/499 pages) - [ ] 2% (10/499 pages) - [= ] 4% (20/499 pages) - [= ] 6% (30/499 pages) - ... - [============================= ] 98% (490/499 pages) - [==============================] 100% (499/499 pages) - Verify 127668 bytes of flash - - [ ] 0% (0/499 pages) - [ ] 2% (10/499 pages) - [= ] 4% (20/499 pages) - [= ] 6% (30/499 pages) - ... - [============================= ] 98% (490/499 pages) - [==============================] 100% (499/499 pages) - Verify successful - Set boot flash true - CPU reset. - - - -=Useful Hacks & Non-Programming Information= - -==Your own wireless badge network== -[[DIY TiLDA Badge Network]] has instructions on how to setup your own private badge network using a RaspberryPi and two Ciseco radios. - -==Convert images to TiLDA bitmap format== -* A Python script (via [https://twitter.com/trotmaster99 @trotmaster99]) that converts a monochrome bitmap image into a format suitable for the Tilda can be found [http://pastebin.com/8XeazQjT here]. -* A similar script in Perl to create TiLDA MKe fullscreen bitmaps from XBM: - -<div style ="height:200px;overflow-x:hidden;overflow-y:auto;border: 4px solid orange;"> -'''xbm2mke.pl by [[User:Msemtd]]''' - <nowiki> -#!perl -w -use strict; -# Little script to convert a regular XBM to TiLDA MKe bitmap -# only tested with fullscreen bitmaps! -# Hot file handle magic... -select((select(STDERR), $| = 1)[0]); -select((select(STDOUT), $| = 1)[0]); -sub t(@); -sub d($); -sub chug($); -my $f = shift; -#~ $f = 'blankish.xbm' if not $f; -if(not defined $f or not $f =~ /^(.*)\.xbm$/i){ - die "Usage: gimme an XBM file dude!\n"; -} -my $name = $1; -t "Reading file '$f'..."; -my $data = chug($f); -t "OK"; -my @lines = split /^/, $data; -@lines = grep{chomp; s/^\s+//; s/\s+$//; length;} @lines; -#~ t d \@lines; -my($width, $height) = (0,0); -my @head = @lines[0..5]; -foreach(@head){ - if(/_width\s+(\d+)/){$width = $1;} - if(/_height\s+(\d+)/){$height = $1;} -} -t "width x height = $width x $height"; -my @k; -foreach(@lines){ push @k, split /,/; } -@k = grep { s/^.*(0x[0-9A-Fa-f]{1,2}).*$/$1/o; /(0x[0-9A-Fa-f]{1,2})/o } @k; -#~ t d \@k; -my $bc = scalar(@k); -t "Pulled out $bc hex bytes"; -if($bc != $width * $height / 8) { - die "byte count $bc does not match that expected for w x h"; -} -t "OK - reorder bytes for MKe bitmap"; -my $wb = int($width/8) + (($width & 0x07) ? 1: 0); -t "width in whole bytes for $width pixels = $wb"; -my @mke; -for(my $col = 0; $col < $wb; $col++){ - for(my $row = $height - 1; $row >= 0; $row--){ - my $idx = ($row * $wb) + $col; - my $val = $k[$idx]; - #~ t "Column $col + Row $row = idx $idx = $val"; - push @mke, $val; - } -} -my $out = "static const uint8_t ".uc($name)."_BM[] = {\n" - ." $width, // width\n" - ." $height , // height\n"; -#~ $out .= join(", ", @mke); -while(scalar @mke){ - $out .= join(", ", splice(@mke, 0, 16)).",\n"; -} -$out .= "};\n"; -# meh, just print it out -t $out; - -sub t(@) { - foreach (@_) { - print STDOUT "$_\n"; - } -} -sub d($) { - require Data::Dumper; - my $s = $_[0]; - my $d = Data::Dumper::Dumper($s); - $d =~ s/^\$VAR1 =\s*//; - $d =~ s/;$//; - chomp $d; - return $d; -} -sub chug($) { - my $filename = shift; - local *F; - open F, "< $filename" or die "Couldn't open `$filename': $!"; - local $/ = undef; - return <F>; -} # F automatically closed - -</nowiki> -</div> - -= Firmware Documentation = -== Debugging == -===Enabling the USB serial debug log messages=== -To enable the debug logging you must uncomment the following line in [https://github.com/emfcamp/Mk2-Firmware/blob/master/hardware/emfcamp/sam/libraries/debug/debug.h#L42 hardware/emfcamp/sam/libraries/debug/debug.h] - - // Enable debug task and output - // #define DEBUG 1 - -===Tilda::log(String text)=== - -This logs “text” to the serial console. To read it connect to it via the Arduino IDE Serial Monitor. Don’t use “SerialUSB.println” or similar -- it’s not thread-safe and you might end up with utter nonsense. - -===Debugging using the JTAG interface=== -The JTAG interface on the board provides powerful debugging facilities like breakpoints, backtraces, dumping memory, inspecting variables, checking task states, catching exeptions etc. To make this to work requires additional hardware and software, see [[TiLDA Debugging using JTAG]]. - -== Buttons == -The badge has 8 buttons: Up, Down, Left, Right, Center (on the joystick), A, B and Light. You can use arduino-style “digitalRead(BUTTON_RIGHT)” to read the current status of any button, but you can’t define your own interrupt (because we already did that). This doesn’t mean you can’t wait for a certain button to be pressed, it just means you have to approach it slightly differently: - -Example: A simple app displaying the button code - void ButtonApp::task() { - ButtonSubscription allButtons = Tilda::createButtonSubscription(LIGHT | A | B | UP | DOWN | LEFT | RIGHT | CENTER); - - while(true) { - Button button = allButtons.waitForPress(1000); - if (button == A) { - debug::log(“You pressed button A”); - } else if (button == LEFT) { - debug::log(“You pressed LEFT”); - } else if (button == NONE) { - debug::log(“No button has been pressed in 1000ms”); - } - } - } - - -===ButtonSubscription Tilda::createButtonSubscription(<buttons>)=== - -Registers a subscriptions for a defined set of buttons and returns a ButtonSubscription. Multiple Buttons can be combined via “|” (see example above). One button can not be subscribed by more than 10 subscriptions (which shouldn’t really happen, but keep it in mind). - -Don’t use this function in a constructor, it requires FreeRTOS to be running. Using it inside the task() function is the only safe place for it. - -===Button ButtonSubscription::waitForPress(TimeInTicks timeout)=== - -This is normally called in a loop. It causes the task to block until one of the buttons has been pressed. If the timeout occurs before any button has been pressed “NONE” will be returned. - -===ButtonSubscription::waitForPress()=== - -The same as above, but without the timeout. - -===ButtonSubscription::clear()=== - -This should be called after an App has been suspended, just before it’s going to be resumed. It causes the Queue to be cleared which could otherwise lead to buttons being reported that have been pressed while other apps were in the foreground. Have a look at the FlashLightApp for an example. - -==LEDs== -===Tilda::setLedColor(Led led, Color color);=== -===Tilde::setLedColor(Color color);=== - -Sets the color of all or one led. Color is an object that takes red, green and blue as a value between 0 and 255 each. If no led is defined both leds will be set to the same color. - -Example: A simple color-changing task - void ColorfulTask::task() { - while(true) { - Tilda::setLedColor(LED1, {255, 0, 0}); // Red - Tilda::setLedColor(LED2, {0, 255, 0}); // Green - Tilda::delay(300); - Tilda::setLedColor(LED1, {0, 255, 0}); // Green - Tilda::setLedColor(LED2, {0, 0, 255}); // Blue - Tilda::delay(300); - Tilda::setLedColor(LED1, {0, 0, 255}); // Blue - Tilda::setLedColor(LED2, {255, 0, 0}); // Red - Tilda::delay(300); - } - } - -==Display== - -The Display Library is based on GLCDv3 (http://playground.arduino.cc/Code/GLCDks0108), docs (http://code.google.com/p/glcd-arduino/source/browse/trunk/glcd/doc/GLCD_Documentation.pdf) but adapted to support our screen. The Init routine is called in the setup, and the LCDTask takes care of ensuring the screen is updated every 40ms if required (Unlike the original GLCD library, screen updates are decoupled from the graphics routines.) - -Also available is M2tklib (https://code.google.com/p/m2tklib/) which is a nice toolkit library. Further details on using this will come later, but expect the main loop to be handled for you, and just passing the menu structure you require for your app. - -Right now, you can call the GLCD functions directly with GLCD.DrawBitmap() for example. This is going to change to be accessed through the GUITask class in the near future, to ensure only one task at a time writes to the screen. Expect this to be simply GUITask in place of GLCD, along with a registering a redraw call back to GUITask. The bitmap format, by the way, is rather unconventional but there are a couple of utility scripts to convert popular formats down in the hacking section below - you can grab the SponsorsApp.h as an example and swap out the bitmap array with one of your choosing. - -Extra features that are included, GLCD.SetRotation() will handle rotation of the screen for you, and GLCD.CurrentWidth() and GLCD.CurrentHeight will give you the correct Width and Height for the current orientation. GLCD.Width and GLCD.Height constants are not available, and the GLCD predefined Text areas will not be rotated for you, if you require this define your own text areas. - -Note that one function was not ported to the badge version of GLCD, "Printf", you'll have to cope without it. - -== Sound == -There's a fully working Piezo on board! - -== IMU == -=== Tilda::getOrientation === -returns " ORIENTATION_HELD", "ORIENTATION_RIGHT" (joystick to the right of the screen), "ORIENTATION_HUNG" or "ORIENTATION_LEFT" - -== Flash Storage == -We have 2mb of flash storage, but we're not using it in the main firmware - Please get this working! -== Data: Schedule == -===Tilda::getDataStore().getSchedule(day, location) === -== Date: Weather Forecast == -===Tilda::getDataStore().getWeatherForecast()=== -== Radio == -There's no way of sending messages in the current version of the firmware, sorry :( - -== Time == - -=== Tilda::delay(uint16_t delayInMs) === - -Works like Arduino’s delay(), but is FreeRTOS-safe. It’s safe to use this function before FreeRTOS has started. - -=== tilda::getClock() === - -Returns an instance of https://github.com/MarkusLange/Arduino-Due-RTC-Library/blob/master/rtc_clock.h - -==Settings== -===uint16_t tilda::getBadgeId()=== - - -==Battery== -===float TiLDA::getBatteryVoltage()=== -Returns the current voltage as a float - -===uint8_t TiLDA::getBatteryPercent()=== -Returns the current voltage as a percentage - -===uint8_t TiLDA::getChargeState()=== -Returns the charge state - -0 Charging -1 Not Charging - 5xfqayqqs3c78vps545ab4o0lyu40rv - - - - TiLDA MKe/Full Specification - 0 - 9 - - 23 - 22 - 2015-05-01T16:20:11Z - - Thinkl33t - 2 - - 23 - wikitext - text/x-wiki - The following hardware has been included on the badge. - -* [http://www.atmel.com/products/microcontrollers/arm/sam3x.aspx Atmel ATSAM3X8E] -** This is the same chip as the [http://arduino.cc/en/Main/ArduinoBoardDue Arduino Due] and gives us the base platform for the badge -** 32bit ARM Cortex M3 * 84MHz -** 512KBytes Flash RAM -** 96KBytes of SRAM -* A 128x64 pixel monochrome LCD display -* [http://shop.ciseco.co.uk/srf-wireless-rf-radio-surface-mount/ Ciseco SRF Radio] -** 868Mhz RF Transceiver -** Simple UART interface -** Low power sleep mode -* [http://www.invensense.com/mems/gyro/mpu6050.html MPU-6050] 3-axis Accelerometer and 3-axis gyro -** I2C interface -** Tri-Axis angular rate sensor (gyro) with a sensitivity up to 131 LSBs/dps and a full-scale range of ±250, ±500, ±1000, and ±2000dps -** Tri-Axis accelerometer with a programmable full scale range of ±2g, ±4g, ±8g and ±16g -** Digital Motion Processing™ (DMP™) engine offloads complex MotionFusion, sensor timing synchronisation and gesture detection -* PMIC & LiPo -* Joystick, 4 way with click -* Buttons -* RGB LEDs -* IR Transmitter -* Arduino Headers -* Pads for wearable tech - 5n5kh4e9qaf5m5ivfmjbg0qf6chhecz - - - - UHB-IF - 0 - 83 - - 511 - 509 - 2024-05-30T20:20:04Z - - Vishnee - 93 - - 511 - wikitext - text/x-wiki - The Unnecessary Hexpansion Bureaucracy Implementers Forum (UHB-IF) exists to implement unnecessary hexpansion bureaucracy. - -The only way to obtain a Vendor ID to use with hexpansion EEPROMs is via the UHB-IF. You will need a vendor ID to make a valid hexpansion EEPROM header. -UHB-IF makes sure that Vendor IDs used by hexpansions are inconvenient to obtain. To obtain a Vendor ID, fill out the right UHB-IF form. Forms are available from authorized representatives of the UHB-IF. The authorized representative at EMF2024 is the [https://wiki.emfcamp.org/2024/wiki/ScottishConsulate|Scottish Consulate]. To request the right form from the Scottish Consulate, please fill in [https://usercontent.irccloud-cdn.com/file/A6xrTR6Z/Consulate%20Scot%20REQ1.pdf form REQ1] and present it in person to the Scottish Consulate during their posted hours of operation. Some copies of REQ1 might be available at the badge team and/or Scottish Consulate. -For further information about how the Scottish Consulate handles procedures can be found in [https://scottishconsulate.org/right_link| their wiki]. - -Organizations wishing to use the legacy REQ-9 method of application should contact the authorized representative for further instructions. - -[[UHB-IF/Issued IDs]] - - -In defiance of the UHB-IF, rebel hackers have homesteaded on some vendor IDs. They are linked below: - -[[UHB-IF/Uncontrolled IDs]] - -The UHB-IF does not approve of unbureaucratic mechanisms like this, but is powerless to do anything about them. - n1rodduu347w92k289width4ijnljws - - - - UHB-IF/Issued IDs - 0 - 86 - - 517 - 516 - 2024-06-02T16:52:43Z - - MatthewWilkes - 69 - - 517 - wikitext - text/x-wiki - These VIDs are properly issued by the UHB-IF. This may only be edited by authorised representatives of the VID owner. - -== VID=0xBAD3 == -Used by the EMFCamp Badge Team for official hexpansions and frontboards. -{| class="wikitable" style="margin:auto" -|+ devices with VID=0xBAD3 -|- -! PID !! Name !! Description || Author || Link to source -|- -| 0x2400 || TwentyTwentyFour || The frontboard for 2024's badge || Badge Team || -|} - - -== VID=0x4291 == -Used by Matt Wilkes - -{| class="wikitable" style="margin:auto" -|+ devices with VID=0x1337 -|- -! PID !! Name !! Description || Author || Link to source -|- -| 0x5e6a || MD Interface || Sega Megadrive Controller Adapter || Matt W || N/A || -! -|} - -== VID=0x0023 == -Used by Uglyhack - -{| class="wikitable" style="margin:auto" -|+ devices with VID=0x0023 -|- -! PID !! Name !! Description || Author || Link to source -|- -| 0x0001 || MCP3021 || MCP3021 board, with EEPROM and potentiometer || Uglyhack || -|} - -== VID=0x1337 == -Used by thinkl33t - -{| class="wikitable" style="margin:auto" -|+ devices with VID=0x1337 -|- -! PID !! Name !! Description || Author || Link to source -|- -| 0x9009 || Googly Eye || Googly Eye Hexpansion with Pattern Matching || thinkl33t || [https://github.com/emfcamp/badge-2024-addons/tree/main/thinkl33t/googly-eye-hexpansion] -|} - 0xqsydcu93xhcty7s8hkolh7szab99r - - - - UHB-IF/Uncontrolled IDs - 0 - 84 - - 519 - 518 - 2024-07-22T21:07:15Z - - Mich181189 - 98 - - /* VID=0xcafe */ Add 0x1936 for something I'm working on - 519 - wikitext - text/x-wiki - These VIDs were taken over by the hacker community without the [[UHB-IF]]'s permission. As they are in use, there is no way to enforce exclusivity for them, and therefore the UHB-IF cannot assign them to anyone else. They are self-managed by the community using them. Add your hexpansion PID to the list to ensure nobody else uses the same identifiers. Please add in numeric order to make searching easier. - -== VID=0xf055 == -Used for open hardware hexpansions. -{| class="wikitable" style="margin:auto" -|+ devices with VID=0xf055 -|- -! PID !! Name !! Description || Author || Link to source -|- -| 0x0000 || Example1 || This is an example entry || H.Acker || [https://github.com/emfcamp/badge-2024-addons] -|- -| 0x???? || Template || This is a template entry - please edit || YourNickHere || [https://github.com/emfcamp/badge-2024-addons] -|- -| 0x4247 || GCHQ.NET Quest Marker || Quest marker for Great Camp Hexpansion Quest || GCHQ.NET || [https://github.com/gchq-net/hexpansion_hardware] -|- -| 0x8426 || "Legacy" connector adapter || Shitty add-ons? TiDAL projects? I2C sensors? Connect them easy. || dratini0 || [https://github.com/dratini0/legacy-adapter-hexpansion] -|- -| 0x8427 || HUB75 hexpansion || I think the Tildagon can drive an LED wall panel. || dratini0 || [https://github.com/dratini0/hub75-hexpansion] -|- -| 0x9009 || Googly Eye || Googly Eye Hexpansion || thinkl33t || [https://github.com/emfcamp/badge-2024-addons/thinkl33t/] -|} - -== VID=0xcafe == -Used for any kind of hexpansion. -{| class="wikitable" style="margin:auto" -|+ devices with VID=0xcafe -|- -! PID !! Name !! Description || Author || Link/image -|- -| 0x0000 || Example1 || This is an example entry || H.Acker || [https://github.com/emfcamp/badge-2024-addons] -|- -| 0x0191 || Maker Space Badge || The Maker Space logo with LEDs, ducks and rabbits. || Dan Nixon || [https://github.com/DanNixon/hexpansions/tree/main/makerspace-badge] -|- -| 0x0CA7 || Cat ears || Cat ears with neopixels || Rox || tbd -|- -| 0x1936 || (A Very Daft Idea) || Placeholder for something I'm working on - Details soon. Hardware built, just needs some software (unfortunately probably with badge firmware changes) || mich181189 || Coming Soon -|- -| 0x5BAA || Janky Machine|| What even is art, really? || [https://danny.makesthings.work/ walkerdanny] || TBD -|- -| 0x5107 || Solar Panel || Poorly thought through solar range extender || Coral (Correlation) || [https://empty.cafe/@coral/112378355746353006] -|- -| 0x5E6A || MD Interface || Control the badge with SEGA Megadrive 3 button controllers || [[User:MatthewWilkes|Matthew Wilkes]] || TBC -|- -| 0xBEE5 || Nullsector Authenticator || <code>DESCRIPTION REDACTED BY POLYBIUS BIOTECH SECURITY</code> || [[User:Graham_Sutherland|Graham Sutherland]] || N/A -|- -| 0xCAFF || Caffeine Jitters|| When the second Club Mate hits || [https://danny.makesthings.work/ walkerdanny] || TBD -|- -| 0xCBCA || HexDrive || Dual Motor || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xCBCB || HexDrive || Dual Motor or 4 Servo Driver (uncommitted) || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xCBCC || HexDrive || 4 Servo Driver || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xCBCD || HexDrive || Single Motor and 2 Servo Driver || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xCBCE || HexSense || Line Sensor Interface || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xCBCF || HexSense || ToF Range Sensor Interface || [[User:Robotmad|Robotmad]] || [https://github.com/TeamRobotmad/HexDrive] -|- -| 0xD15C || Flopagon || 16MB SPI Flash storage || [https://nathandumont.com Nathan Dumont] || TBD -|- -| 0xDC01 || Omni Wheel || A single motor/encoder with omni wheel || [https://dumont-cybernetics.net Nathan Dumont] || [https://github.com/hairymnstr/omni-wheel-hexpansion] -|- -| 0x???? || Template || This is a template entry - please edit || YourNickHere || [https://github.com/emfcamp/badge-2024-addons] -|} - eq3r0k346f8mpezsfjf50rtf5j5b4uo - - - diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..4baa539 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,57 @@ +site_name: EMF Legacy Badge Documentation +site_description: "Documentation for the EMF Badges 2012-2022" +site_url: https://badge.emfcamp.org +repo_url: https://github.com/emfcamp/badge-website +theme: + name: material +markdown_extensions: + - attr_list + - md_in_html + - codehilite + - fenced_code + - admonition + - sane_lists + - pymdownx.details + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + +plugins: + - glightbox: + caption_position: bottom + - mkdocs-nav-weight + - include-markdown + - minify: + minify_html: true + minify_css: true + minify_js: true + minify_css: true + cache_safe: true + - social: + cards_layout_options: + background_color: "#528329" + color: "#ffffff" + font-family: "Roboto" + - search + - spellcheck: + backends: # the backends you want to use + - codespell: # or nested configs + dictionaries: [clear, rare] + + # ignore words in tags + ignore_code: yes + + # minimum length of words to consider + min_length: 2 + + # maximum number of capital letters in a word + max_capital: 1 + + # keep unicode characters + allow_unicode: yes + + # whether to only check in strict mode + strict_only: no diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bc09906 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "badge-website" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [] diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..673a3d3 --- /dev/null +++ b/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "badge-website" +version = "0.1.0" +source = { virtual = "." } From 32841d06fa76987a9f21cad79a9a5fe33be754f5 Mon Sep 17 00:00:00 2001 From: Bob Clough Date: Mon, 13 Oct 2025 17:10:34 +0100 Subject: [PATCH 4/5] more WIP --- CI.yml => .github/workflows/CI.yml | 0 .gitignore | 1 + .python-version | 1 - README.md | 0 main.py | 6 - mkdocs.yml | 2 +- pyproject.toml | 15 +- uv.lock | 1045 +++++++++++++++++++++++++++- 8 files changed, 1059 insertions(+), 11 deletions(-) rename CI.yml => .github/workflows/CI.yml (100%) delete mode 100644 .python-version delete mode 100644 README.md delete mode 100644 main.py diff --git a/CI.yml b/.github/workflows/CI.yml similarity index 100% rename from CI.yml rename to .github/workflows/CI.yml diff --git a/.gitignore b/.gitignore index 16d3c4d..cdc9f82 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .cache +.venv diff --git a/.python-version b/.python-version deleted file mode 100644 index 2c07333..0000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.11 diff --git a/README.md b/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/main.py b/main.py deleted file mode 100644 index 1d2fbf3..0000000 --- a/main.py +++ /dev/null @@ -1,6 +0,0 @@ -def main(): - print("Hello from badge-website!") - - -if __name__ == "__main__": - main() diff --git a/mkdocs.yml b/mkdocs.yml index 4baa539..2031392 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: EMF Legacy Badge Documentation +site_name: EMF Badge Documentation site_description: "Documentation for the EMF Badges 2012-2022" site_url: https://badge.emfcamp.org repo_url: https://github.com/emfcamp/badge-website diff --git a/pyproject.toml b/pyproject.toml index bc09906..b21a266 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,5 +3,16 @@ name = "badge-website" version = "0.1.0" description = "Add your description here" readme = "README.md" -requires-python = ">=3.11" -dependencies = [] +requires-python = ">=3.12" +dependencies = [ + "codespell>=2.4.1", + "flake8-markdown>=0.6.0", + "mkdocs>=1.6.1", + "mkdocs-git-committers-plugin>=0.2.3", + "mkdocs-glightbox>=0.5.1", + "mkdocs-include-markdown-plugin>=7.2.0", + "mkdocs-material[imaging]>=9.6.21", + "mkdocs-minify-plugin>=0.8.0", + "mkdocs-nav-weight>=0.3.0", + "mkdocs-spellcheck>=1.1.2", +] diff --git a/uv.lock b/uv.lock index 673a3d3..dc4a32d 100644 --- a/uv.lock +++ b/uv.lock @@ -1,8 +1,1051 @@ version = 1 revision = 3 -requires-python = ">=3.11" +requires-python = ">=3.12" +resolution-markers = [ + "python_full_version >= '3.14' and platform_python_implementation != 'PyPy'", + "python_full_version < '3.14' and platform_python_implementation != 'PyPy'", + "platform_python_implementation == 'PyPy'", +] + +[[package]] +name = "babel" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, +] + +[[package]] +name = "backrefs" +version = "5.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/a7/312f673df6a79003279e1f55619abbe7daebbb87c17c976ddc0345c04c7b/backrefs-5.9.tar.gz", hash = "sha256:808548cb708d66b82ee231f962cb36faaf4f2baab032f2fbb783e9c2fdddaa59", size = 5765857, upload-time = "2025-06-22T19:34:13.97Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/4d/798dc1f30468134906575156c089c492cf79b5a5fd373f07fe26c4d046bf/backrefs-5.9-py310-none-any.whl", hash = "sha256:db8e8ba0e9de81fcd635f440deab5ae5f2591b54ac1ebe0550a2ca063488cd9f", size = 380267, upload-time = "2025-06-22T19:34:05.252Z" }, + { url = "https://files.pythonhosted.org/packages/55/07/f0b3375bf0d06014e9787797e6b7cc02b38ac9ff9726ccfe834d94e9991e/backrefs-5.9-py311-none-any.whl", hash = "sha256:6907635edebbe9b2dc3de3a2befff44d74f30a4562adbb8b36f21252ea19c5cf", size = 392072, upload-time = "2025-06-22T19:34:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/9d/12/4f345407259dd60a0997107758ba3f221cf89a9b5a0f8ed5b961aef97253/backrefs-5.9-py312-none-any.whl", hash = "sha256:7fdf9771f63e6028d7fee7e0c497c81abda597ea45d6b8f89e8ad76994f5befa", size = 397947, upload-time = "2025-06-22T19:34:08.172Z" }, + { url = "https://files.pythonhosted.org/packages/10/bf/fa31834dc27a7f05e5290eae47c82690edc3a7b37d58f7fb35a1bdbf355b/backrefs-5.9-py313-none-any.whl", hash = "sha256:cc37b19fa219e93ff825ed1fed8879e47b4d89aa7a1884860e2db64ccd7c676b", size = 399843, upload-time = "2025-06-22T19:34:09.68Z" }, + { url = "https://files.pythonhosted.org/packages/fc/24/b29af34b2c9c41645a9f4ff117bae860291780d73880f449e0b5d948c070/backrefs-5.9-py314-none-any.whl", hash = "sha256:df5e169836cc8acb5e440ebae9aad4bf9d15e226d3bad049cf3f6a5c20cc8dc9", size = 411762, upload-time = "2025-06-22T19:34:11.037Z" }, + { url = "https://files.pythonhosted.org/packages/41/ff/392bff89415399a979be4a65357a41d92729ae8580a66073d8ec8d810f98/backrefs-5.9-py39-none-any.whl", hash = "sha256:f48ee18f6252b8f5777a22a00a09a85de0ca931658f1dd96d4406a34f3748c60", size = 380265, upload-time = "2025-06-22T19:34:12.405Z" }, +] [[package]] name = "badge-website" version = "0.1.0" source = { virtual = "." } +dependencies = [ + { name = "codespell" }, + { name = "flake8-markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-git-committers-plugin" }, + { name = "mkdocs-glightbox" }, + { name = "mkdocs-include-markdown-plugin" }, + { name = "mkdocs-material", extra = ["imaging"] }, + { name = "mkdocs-minify-plugin" }, + { name = "mkdocs-nav-weight" }, + { name = "mkdocs-spellcheck" }, +] + +[package.metadata] +requires-dist = [ + { name = "codespell", specifier = ">=2.4.1" }, + { name = "flake8-markdown", specifier = ">=0.6.0" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-git-committers-plugin", specifier = ">=0.2.3" }, + { name = "mkdocs-glightbox", specifier = ">=0.5.1" }, + { name = "mkdocs-include-markdown-plugin", specifier = ">=7.2.0" }, + { name = "mkdocs-material", extras = ["imaging"], specifier = ">=9.6.21" }, + { name = "mkdocs-minify-plugin", specifier = ">=0.8.0" }, + { name = "mkdocs-nav-weight", specifier = ">=0.3.0" }, + { name = "mkdocs-spellcheck", specifier = ">=1.1.2" }, +] + +[[package]] +name = "bracex" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/9a/fec38644694abfaaeca2798b58e276a8e61de49e2e37494ace423395febc/bracex-2.6.tar.gz", hash = "sha256:98f1347cd77e22ee8d967a30ad4e310b233f7754dbf31ff3fceb76145ba47dc7", size = 26642, upload-time = "2025-06-22T19:12:31.254Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/2a/9186535ce58db529927f6cf5990a849aa9e052eea3e2cfefe20b9e1802da/bracex-2.6-py3-none-any.whl", hash = "sha256:0b0049264e7340b3ec782b5cb99beb325f36c3782a32e36e876452fd49a09952", size = 11508, upload-time = "2025-06-22T19:12:29.781Z" }, +] + +[[package]] +name = "cairocffi" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/c5/1a4dc131459e68a173cbdab5fad6b524f53f9c1ef7861b7698e998b837cc/cairocffi-1.7.1.tar.gz", hash = "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", size = 88096, upload-time = "2024-06-18T10:56:06.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d8/ba13451aa6b745c49536e87b6bf8f629b950e84bd0e8308f7dc6883b67e2/cairocffi-1.7.1-py3-none-any.whl", hash = "sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f", size = 75611, upload-time = "2024-06-18T10:55:59.489Z" }, +] + +[[package]] +name = "cairosvg" +version = "2.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cairocffi" }, + { name = "cssselect2" }, + { name = "defusedxml" }, + { name = "pillow" }, + { name = "tinycss2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/b9/5106168bd43d7cd8b7cc2a2ee465b385f14b63f4c092bb89eee2d48c8e67/cairosvg-2.8.2.tar.gz", hash = "sha256:07cbf4e86317b27a92318a4cac2a4bb37a5e9c1b8a27355d06874b22f85bef9f", size = 8398590, upload-time = "2025-05-15T06:56:32.653Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/48/816bd4aaae93dbf9e408c58598bc32f4a8c65f4b86ab560864cb3ee60adb/cairosvg-2.8.2-py3-none-any.whl", hash = "sha256:eab46dad4674f33267a671dce39b64be245911c901c70d65d2b7b0821e852bf5", size = 45773, upload-time = "2025-05-15T06:56:28.552Z" }, +] + +[[package]] +name = "certifi" +version = "2025.10.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", size = 164519, upload-time = "2025-10-05T04:12:15.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de", size = 163286, upload-time = "2025-10-05T04:12:14.03Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "click" +version = "8.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" }, +] + +[[package]] +name = "codespell" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/e0/709453393c0ea77d007d907dd436b3ee262e28b30995ea1aa36c6ffbccaf/codespell-2.4.1.tar.gz", hash = "sha256:299fcdcb09d23e81e35a671bbe746d5ad7e8385972e65dbb833a2eaac33c01e5", size = 344740, upload-time = "2025-01-28T18:52:39.411Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/01/b394922252051e97aab231d416c86da3d8a6d781eeadcdca1082867de64e/codespell-2.4.1-py3-none-any.whl", hash = "sha256:3dadafa67df7e4a3dbf51e0d7315061b80d265f9552ebd699b3dd6834b47e425", size = 344501, upload-time = "2025-01-28T18:52:37.057Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/9b/e301418629f7bfdf72db9e80ad6ed9d1b83c487c471803eaa6464c511a01/cryptography-46.0.2.tar.gz", hash = "sha256:21b6fc8c71a3f9a604f028a329e5560009cc4a3a828bfea5fcba8eb7647d88fe", size = 749293, upload-time = "2025-10-01T00:29:11.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/98/7a8df8c19a335c8028414738490fc3955c0cecbfdd37fcc1b9c3d04bd561/cryptography-46.0.2-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:f3e32ab7dd1b1ef67b9232c4cf5e2ee4cd517d4316ea910acaaa9c5712a1c663", size = 7261255, upload-time = "2025-10-01T00:27:22.947Z" }, + { url = "https://files.pythonhosted.org/packages/c6/38/b2adb2aa1baa6706adc3eb746691edd6f90a656a9a65c3509e274d15a2b8/cryptography-46.0.2-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1fd1a69086926b623ef8126b4c33d5399ce9e2f3fac07c9c734c2a4ec38b6d02", size = 4297596, upload-time = "2025-10-01T00:27:25.258Z" }, + { url = "https://files.pythonhosted.org/packages/e4/27/0f190ada240003119488ae66c897b5e97149292988f556aef4a6a2a57595/cryptography-46.0.2-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb7fb9cd44c2582aa5990cf61a4183e6f54eea3172e54963787ba47287edd135", size = 4450899, upload-time = "2025-10-01T00:27:27.458Z" }, + { url = "https://files.pythonhosted.org/packages/85/d5/e4744105ab02fdf6bb58ba9a816e23b7a633255987310b4187d6745533db/cryptography-46.0.2-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:9066cfd7f146f291869a9898b01df1c9b0e314bfa182cef432043f13fc462c92", size = 4300382, upload-time = "2025-10-01T00:27:29.091Z" }, + { url = "https://files.pythonhosted.org/packages/33/fb/bf9571065c18c04818cb07de90c43fc042c7977c68e5de6876049559c72f/cryptography-46.0.2-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:97e83bf4f2f2c084d8dd792d13841d0a9b241643151686010866bbd076b19659", size = 4017347, upload-time = "2025-10-01T00:27:30.767Z" }, + { url = "https://files.pythonhosted.org/packages/35/72/fc51856b9b16155ca071080e1a3ad0c3a8e86616daf7eb018d9565b99baa/cryptography-46.0.2-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:4a766d2a5d8127364fd936572c6e6757682fc5dfcbdba1632d4554943199f2fa", size = 4983500, upload-time = "2025-10-01T00:27:32.741Z" }, + { url = "https://files.pythonhosted.org/packages/c1/53/0f51e926799025e31746d454ab2e36f8c3f0d41592bc65cb9840368d3275/cryptography-46.0.2-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fab8f805e9675e61ed8538f192aad70500fa6afb33a8803932999b1049363a08", size = 4482591, upload-time = "2025-10-01T00:27:34.869Z" }, + { url = "https://files.pythonhosted.org/packages/86/96/4302af40b23ab8aa360862251fb8fc450b2a06ff24bc5e261c2007f27014/cryptography-46.0.2-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:1e3b6428a3d56043bff0bb85b41c535734204e599c1c0977e1d0f261b02f3ad5", size = 4300019, upload-time = "2025-10-01T00:27:37.029Z" }, + { url = "https://files.pythonhosted.org/packages/9b/59/0be12c7fcc4c5e34fe2b665a75bc20958473047a30d095a7657c218fa9e8/cryptography-46.0.2-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:1a88634851d9b8de8bb53726f4300ab191d3b2f42595e2581a54b26aba71b7cc", size = 4950006, upload-time = "2025-10-01T00:27:40.272Z" }, + { url = "https://files.pythonhosted.org/packages/55/1d/42fda47b0111834b49e31590ae14fd020594d5e4dadd639bce89ad790fba/cryptography-46.0.2-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:be939b99d4e091eec9a2bcf41aaf8f351f312cd19ff74b5c83480f08a8a43e0b", size = 4482088, upload-time = "2025-10-01T00:27:42.668Z" }, + { url = "https://files.pythonhosted.org/packages/17/50/60f583f69aa1602c2bdc7022dae86a0d2b837276182f8c1ec825feb9b874/cryptography-46.0.2-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f13b040649bc18e7eb37936009b24fd31ca095a5c647be8bb6aaf1761142bd1", size = 4425599, upload-time = "2025-10-01T00:27:44.616Z" }, + { url = "https://files.pythonhosted.org/packages/d1/57/d8d4134cd27e6e94cf44adb3f3489f935bde85f3a5508e1b5b43095b917d/cryptography-46.0.2-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bdc25e4e01b261a8fda4e98618f1c9515febcecebc9566ddf4a70c63967043b", size = 4697458, upload-time = "2025-10-01T00:27:46.209Z" }, + { url = "https://files.pythonhosted.org/packages/d1/2b/531e37408573e1da33adfb4c58875013ee8ac7d548d1548967d94a0ae5c4/cryptography-46.0.2-cp311-abi3-win32.whl", hash = "sha256:8b9bf67b11ef9e28f4d78ff88b04ed0929fcd0e4f70bb0f704cfc32a5c6311ee", size = 3056077, upload-time = "2025-10-01T00:27:48.424Z" }, + { url = "https://files.pythonhosted.org/packages/a8/cd/2f83cafd47ed2dc5a3a9c783ff5d764e9e70d3a160e0df9a9dcd639414ce/cryptography-46.0.2-cp311-abi3-win_amd64.whl", hash = "sha256:758cfc7f4c38c5c5274b55a57ef1910107436f4ae842478c4989abbd24bd5acb", size = 3512585, upload-time = "2025-10-01T00:27:50.521Z" }, + { url = "https://files.pythonhosted.org/packages/00/36/676f94e10bfaa5c5b86c469ff46d3e0663c5dc89542f7afbadac241a3ee4/cryptography-46.0.2-cp311-abi3-win_arm64.whl", hash = "sha256:218abd64a2e72f8472c2102febb596793347a3e65fafbb4ad50519969da44470", size = 2927474, upload-time = "2025-10-01T00:27:52.91Z" }, + { url = "https://files.pythonhosted.org/packages/6f/cc/47fc6223a341f26d103cb6da2216805e08a37d3b52bee7f3b2aee8066f95/cryptography-46.0.2-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:bda55e8dbe8533937956c996beaa20266a8eca3570402e52ae52ed60de1faca8", size = 7198626, upload-time = "2025-10-01T00:27:54.8Z" }, + { url = "https://files.pythonhosted.org/packages/93/22/d66a8591207c28bbe4ac7afa25c4656dc19dc0db29a219f9809205639ede/cryptography-46.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7155c0b004e936d381b15425273aee1cebc94f879c0ce82b0d7fecbf755d53a", size = 4287584, upload-time = "2025-10-01T00:27:57.018Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3e/fac3ab6302b928e0398c269eddab5978e6c1c50b2b77bb5365ffa8633b37/cryptography-46.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a61c154cc5488272a6c4b86e8d5beff4639cdb173d75325ce464d723cda0052b", size = 4433796, upload-time = "2025-10-01T00:27:58.631Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d8/24392e5d3c58e2d83f98fe5a2322ae343360ec5b5b93fe18bc52e47298f5/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:9ec3f2e2173f36a9679d3b06d3d01121ab9b57c979de1e6a244b98d51fea1b20", size = 4292126, upload-time = "2025-10-01T00:28:00.643Z" }, + { url = "https://files.pythonhosted.org/packages/ed/38/3d9f9359b84c16c49a5a336ee8be8d322072a09fac17e737f3bb11f1ce64/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2fafb6aa24e702bbf74de4cb23bfa2c3beb7ab7683a299062b69724c92e0fa73", size = 3993056, upload-time = "2025-10-01T00:28:02.8Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a3/4c44fce0d49a4703cc94bfbe705adebf7ab36efe978053742957bc7ec324/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0c7ffe8c9b1fcbb07a26d7c9fa5e857c2fe80d72d7b9e0353dcf1d2180ae60ee", size = 4967604, upload-time = "2025-10-01T00:28:04.783Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c2/49d73218747c8cac16bb8318a5513fde3129e06a018af3bc4dc722aa4a98/cryptography-46.0.2-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:5840f05518caa86b09d23f8b9405a7b6d5400085aa14a72a98fdf5cf1568c0d2", size = 4465367, upload-time = "2025-10-01T00:28:06.864Z" }, + { url = "https://files.pythonhosted.org/packages/1b/64/9afa7d2ee742f55ca6285a54386ed2778556a4ed8871571cb1c1bfd8db9e/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:27c53b4f6a682a1b645fbf1cd5058c72cf2f5aeba7d74314c36838c7cbc06e0f", size = 4291678, upload-time = "2025-10-01T00:28:08.982Z" }, + { url = "https://files.pythonhosted.org/packages/50/48/1696d5ea9623a7b72ace87608f6899ca3c331709ac7ebf80740abb8ac673/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:512c0250065e0a6b286b2db4bbcc2e67d810acd53eb81733e71314340366279e", size = 4931366, upload-time = "2025-10-01T00:28:10.74Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/9dfc778401a334db3b24435ee0733dd005aefb74afe036e2d154547cb917/cryptography-46.0.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:07c0eb6657c0e9cca5891f4e35081dbf985c8131825e21d99b4f440a8f496f36", size = 4464738, upload-time = "2025-10-01T00:28:12.491Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b1/abcde62072b8f3fd414e191a6238ce55a0050e9738090dc6cded24c12036/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48b983089378f50cba258f7f7aa28198c3f6e13e607eaf10472c26320332ca9a", size = 4419305, upload-time = "2025-10-01T00:28:14.145Z" }, + { url = "https://files.pythonhosted.org/packages/c7/1f/3d2228492f9391395ca34c677e8f2571fb5370fe13dc48c1014f8c509864/cryptography-46.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e6f6775eaaa08c0eec73e301f7592f4367ccde5e4e4df8e58320f2ebf161ea2c", size = 4681201, upload-time = "2025-10-01T00:28:15.951Z" }, + { url = "https://files.pythonhosted.org/packages/de/77/b687745804a93a55054f391528fcfc76c3d6bfd082ce9fb62c12f0d29fc1/cryptography-46.0.2-cp314-cp314t-win32.whl", hash = "sha256:e8633996579961f9b5a3008683344c2558d38420029d3c0bc7ff77c17949a4e1", size = 3022492, upload-time = "2025-10-01T00:28:17.643Z" }, + { url = "https://files.pythonhosted.org/packages/60/a5/8d498ef2996e583de0bef1dcc5e70186376f00883ae27bf2133f490adf21/cryptography-46.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:48c01988ecbb32979bb98731f5c2b2f79042a6c58cc9a319c8c2f9987c7f68f9", size = 3496215, upload-time = "2025-10-01T00:28:19.272Z" }, + { url = "https://files.pythonhosted.org/packages/56/db/ee67aaef459a2706bc302b15889a1a8126ebe66877bab1487ae6ad00f33d/cryptography-46.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:8e2ad4d1a5899b7caa3a450e33ee2734be7cc0689010964703a7c4bcc8dd4fd0", size = 2919255, upload-time = "2025-10-01T00:28:21.115Z" }, + { url = "https://files.pythonhosted.org/packages/d5/bb/fa95abcf147a1b0bb94d95f53fbb09da77b24c776c5d87d36f3d94521d2c/cryptography-46.0.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a08e7401a94c002e79dc3bc5231b6558cd4b2280ee525c4673f650a37e2c7685", size = 7248090, upload-time = "2025-10-01T00:28:22.846Z" }, + { url = "https://files.pythonhosted.org/packages/b7/66/f42071ce0e3ffbfa80a88feadb209c779fda92a23fbc1e14f74ebf72ef6b/cryptography-46.0.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d30bc11d35743bf4ddf76674a0a369ec8a21f87aaa09b0661b04c5f6c46e8d7b", size = 4293123, upload-time = "2025-10-01T00:28:25.072Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5d/1fdbd2e5c1ba822828d250e5a966622ef00185e476d1cd2726b6dd135e53/cryptography-46.0.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bca3f0ce67e5a2a2cf524e86f44697c4323a86e0fd7ba857de1c30d52c11ede1", size = 4439524, upload-time = "2025-10-01T00:28:26.808Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c1/5e4989a7d102d4306053770d60f978c7b6b1ea2ff8c06e0265e305b23516/cryptography-46.0.2-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ff798ad7a957a5021dcbab78dfff681f0cf15744d0e6af62bd6746984d9c9e9c", size = 4297264, upload-time = "2025-10-01T00:28:29.327Z" }, + { url = "https://files.pythonhosted.org/packages/28/78/b56f847d220cb1d6d6aef5a390e116ad603ce13a0945a3386a33abc80385/cryptography-46.0.2-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cb5e8daac840e8879407acbe689a174f5ebaf344a062f8918e526824eb5d97af", size = 4011872, upload-time = "2025-10-01T00:28:31.479Z" }, + { url = "https://files.pythonhosted.org/packages/e1/80/2971f214b066b888944f7b57761bf709ee3f2cf805619a18b18cab9b263c/cryptography-46.0.2-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:3f37aa12b2d91e157827d90ce78f6180f0c02319468a0aea86ab5a9566da644b", size = 4978458, upload-time = "2025-10-01T00:28:33.267Z" }, + { url = "https://files.pythonhosted.org/packages/a5/84/0cb0a2beaa4f1cbe63ebec4e97cd7e0e9f835d0ba5ee143ed2523a1e0016/cryptography-46.0.2-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e38f203160a48b93010b07493c15f2babb4e0f2319bbd001885adb3f3696d21", size = 4472195, upload-time = "2025-10-01T00:28:36.039Z" }, + { url = "https://files.pythonhosted.org/packages/30/8b/2b542ddbf78835c7cd67b6fa79e95560023481213a060b92352a61a10efe/cryptography-46.0.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d19f5f48883752b5ab34cff9e2f7e4a7f216296f33714e77d1beb03d108632b6", size = 4296791, upload-time = "2025-10-01T00:28:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/78/12/9065b40201b4f4876e93b9b94d91feb18de9150d60bd842a16a21565007f/cryptography-46.0.2-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:04911b149eae142ccd8c9a68892a70c21613864afb47aba92d8c7ed9cc001023", size = 4939629, upload-time = "2025-10-01T00:28:39.654Z" }, + { url = "https://files.pythonhosted.org/packages/f6/9e/6507dc048c1b1530d372c483dfd34e7709fc542765015425f0442b08547f/cryptography-46.0.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:8b16c1ede6a937c291d41176934268e4ccac2c6521c69d3f5961c5a1e11e039e", size = 4471988, upload-time = "2025-10-01T00:28:41.822Z" }, + { url = "https://files.pythonhosted.org/packages/b1/86/d025584a5f7d5c5ec8d3633dbcdce83a0cd579f1141ceada7817a4c26934/cryptography-46.0.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:747b6f4a4a23d5a215aadd1d0b12233b4119c4313df83ab4137631d43672cc90", size = 4422989, upload-time = "2025-10-01T00:28:43.608Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/536370418b38a15a61bbe413006b79dfc3d2b4b0eafceb5581983f973c15/cryptography-46.0.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6b275e398ab3a7905e168c036aad54b5969d63d3d9099a0a66cc147a3cc983be", size = 4685578, upload-time = "2025-10-01T00:28:45.361Z" }, + { url = "https://files.pythonhosted.org/packages/15/52/ea7e2b1910f547baed566c866fbb86de2402e501a89ecb4871ea7f169a81/cryptography-46.0.2-cp38-abi3-win32.whl", hash = "sha256:0b507c8e033307e37af61cb9f7159b416173bdf5b41d11c4df2e499a1d8e007c", size = 3036711, upload-time = "2025-10-01T00:28:47.096Z" }, + { url = "https://files.pythonhosted.org/packages/71/9e/171f40f9c70a873e73c2efcdbe91e1d4b1777a03398fa1c4af3c56a2477a/cryptography-46.0.2-cp38-abi3-win_amd64.whl", hash = "sha256:f9b2dc7668418fb6f221e4bf701f716e05e8eadb4f1988a2487b11aedf8abe62", size = 3500007, upload-time = "2025-10-01T00:28:48.967Z" }, + { url = "https://files.pythonhosted.org/packages/3e/7c/15ad426257615f9be8caf7f97990cf3dcbb5b8dd7ed7e0db581a1c4759dd/cryptography-46.0.2-cp38-abi3-win_arm64.whl", hash = "sha256:91447f2b17e83c9e0c89f133119d83f94ce6e0fb55dd47da0a959316e6e9cfa1", size = 2918153, upload-time = "2025-10-01T00:28:51.003Z" }, +] + +[[package]] +name = "csscompressor" +version = "0.9.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/2a/8c3ac3d8bc94e6de8d7ae270bb5bc437b210bb9d6d9e46630c98f4abd20c/csscompressor-0.9.5.tar.gz", hash = "sha256:afa22badbcf3120a4f392e4d22f9fff485c044a1feda4a950ecc5eba9dd31a05", size = 237808, upload-time = "2017-11-26T21:13:08.238Z" } + +[[package]] +name = "cssselect2" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tinycss2" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/86/fd7f58fc498b3166f3a7e8e0cddb6e620fe1da35b02248b1bd59e95dbaaa/cssselect2-0.8.0.tar.gz", hash = "sha256:7674ffb954a3b46162392aee2a3a0aedb2e14ecf99fcc28644900f4e6e3e9d3a", size = 35716, upload-time = "2025-03-05T14:46:07.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/e7/aa315e6a749d9b96c2504a1ba0ba031ba2d0517e972ce22682e3fccecb09/cssselect2-0.8.0-py3-none-any.whl", hash = "sha256:46fc70ebc41ced7a32cd42d58b1884d72ade23d21e5a4eaaf022401c13f0e76e", size = 15454, upload-time = "2025-03-05T14:46:06.463Z" }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, +] + +[[package]] +name = "flake8" +version = "7.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mccabe" }, + { name = "pycodestyle" }, + { name = "pyflakes" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, +] + +[[package]] +name = "flake8-markdown" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/b9/419275fdeb2df233430dcc166956ea521e46e595cbd106b44a4ae4c8574b/flake8_markdown-0.6.0.tar.gz", hash = "sha256:69d2a3d650ad6e995885c46c96963939eb28bd08f1832714ad09717b58848059", size = 4553, upload-time = "2024-12-04T15:00:59.724Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/5d/2b8cec55b51be724945a9046c428140db7685fb7b49ac3fe2fd87f20a60c/flake8_markdown-0.6.0-py3-none-any.whl", hash = "sha256:4aaca329a5322aeace9e1bfdb3e0bb4c0c05cc611a7f4106a467dcb4e0224454", size = 6421, upload-time = "2024-12-04T15:00:57.961Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "htmlmin2" +version = "0.1.13" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/31/a76f4bfa885f93b8167cb4c85cf32b54d1f64384d0b897d45bc6d19b7b45/htmlmin2-0.1.13-py3-none-any.whl", hash = "sha256:75609f2a42e64f7ce57dbff28a39890363bde9e7e5885db633317efbdf8c79a2", size = 34486, upload-time = "2023-03-14T21:28:30.388Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jsmin" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/73/e01e4c5e11ad0494f4407a3f623ad4d87714909f50b17a06ed121034ff6e/jsmin-3.0.1.tar.gz", hash = "sha256:c0959a121ef94542e807a674142606f7e90214a2b3d1eb17300244bbb5cc2bfc", size = 13925, upload-time = "2022-01-16T20:35:59.13Z" } + +[[package]] +name = "markdown" +version = "3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239, upload-time = "2023-11-20T17:51:09.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, +] + +[[package]] +name = "mkdocs-git-committers-plugin" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, + { name = "pygithub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/88/e724563e9ff1b119869ef0704157caa8d7b9b9b4a8a8faf8120aa01620e2/mkdocs-git-committers-plugin-0.2.3.tar.gz", hash = "sha256:77188d8aacc11d5233d6949435670e3d6545ffb7a0e274d56f32ed3984353c61", size = 5379, upload-time = "2023-11-06T17:13:30.207Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/56/15fdbb6afa718a6c9de626bd11672040832ba547c03daf205e295be4e0d4/mkdocs_git_committers_plugin-0.2.3-py3-none-any.whl", hash = "sha256:4ca79efb7e61a72652d3512d61af5c40a4572e36667e1a00032aad524250780d", size = 4340, upload-time = "2023-11-06T17:13:28.979Z" }, +] + +[[package]] +name = "mkdocs-glightbox" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "selectolax" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/72/c03e9d8d2dbe098d7ce5d51309933a1d3aea268965ed097ab16f4b54de15/mkdocs_glightbox-0.5.1.tar.gz", hash = "sha256:7d78a5b045f2479f61b0bbb17742ba701755c56b013e70ac189c9d87a91e80bf", size = 480028, upload-time = "2025-09-04T13:10:29.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/cf/e9a0ce9da269746906fdc595c030f6df66793dad1487abd1699af2ba44f1/mkdocs_glightbox-0.5.1-py3-none-any.whl", hash = "sha256:f47af0daff164edf8d36e553338425be3aab6e34b987d9cbbc2ae7819a98cb01", size = 26431, upload-time = "2025-09-04T13:10:27.933Z" }, +] + +[[package]] +name = "mkdocs-include-markdown-plugin" +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, + { name = "wcmatch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/10/b0b75ac42f4613556a808eee2dad3efe7a7d5079349aa5b9229d863e829f/mkdocs_include_markdown_plugin-7.2.0.tar.gz", hash = "sha256:4a67a91ade680dc0e15f608e5b6343bec03372ffa112c40a4254c1bfb10f42f3", size = 25509, upload-time = "2025-09-28T21:50:50.41Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/f9/783338d1d7fd548c7635728b67a0f8f96d9e6c265aa61c51356c03597767/mkdocs_include_markdown_plugin-7.2.0-py3-none-any.whl", hash = "sha256:d56cdaeb2d113fb66ed0fe4fb7af1da889926b0b9872032be24e19bbb09c9f5b", size = 29548, upload-time = "2025-09-28T21:50:49.373Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.6.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/d5/ab83ca9aa314954b0a9e8849780bdd01866a3cfcb15ffb7e3a61ca06ff0b/mkdocs_material-9.6.21.tar.gz", hash = "sha256:b01aa6d2731322438056f360f0e623d3faae981f8f2d8c68b1b973f4f2657870", size = 4043097, upload-time = "2025-09-30T19:11:27.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/4f/98681c2030375fe9b057dbfb9008b68f46c07dddf583f4df09bf8075e37f/mkdocs_material-9.6.21-py3-none-any.whl", hash = "sha256:aa6a5ab6fb4f6d381588ac51da8782a4d3757cb3d1b174f81a2ec126e1f22c92", size = 9203097, upload-time = "2025-09-30T19:11:24.063Z" }, +] + +[package.optional-dependencies] +imaging = [ + { name = "cairosvg" }, + { name = "pillow" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocs-minify-plugin" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "csscompressor" }, + { name = "htmlmin2" }, + { name = "jsmin" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/67/fe4b77e7a8ae7628392e28b14122588beaf6078b53eb91c7ed000fd158ac/mkdocs-minify-plugin-0.8.0.tar.gz", hash = "sha256:bc11b78b8120d79e817308e2b11539d790d21445eb63df831e393f76e52e753d", size = 8366, upload-time = "2024-01-29T16:11:32.982Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/cd/2e8d0d92421916e2ea4ff97f10a544a9bd5588eb747556701c983581df13/mkdocs_minify_plugin-0.8.0-py3-none-any.whl", hash = "sha256:5fba1a3f7bd9a2142c9954a6559a57e946587b21f133165ece30ea145c66aee6", size = 6723, upload-time = "2024-01-29T16:11:31.851Z" }, +] + +[[package]] +name = "mkdocs-nav-weight" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/08/1b996d23571758287ee4098e16779d2b44b58005dc2b80f20423774d7ce5/mkdocs_nav_weight-0.3.0.tar.gz", hash = "sha256:e4b66f0693aa1d8b82876727f3c5a6aa3c85834069dfd1b5ea23432ff3d862bb", size = 11329, upload-time = "2025-09-09T11:44:33.288Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/ec/12153ca0b5821b8a0a443431da7427df21a3566a96410e744b7cb62465c9/mkdocs_nav_weight-0.3.0-py3-none-any.whl", hash = "sha256:f95b2f2ca3f3125e95c4518ed66df4a1b9082d37840b352a5a3e3c2559276cba", size = 6910, upload-time = "2025-09-09T11:44:32.025Z" }, +] + +[[package]] +name = "mkdocs-spellcheck" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/28/3f52d27adf3e352099388608bccfac84b30e886ca6f7b0cb01d2eb4ef5ae/mkdocs_spellcheck-1.1.2.tar.gz", hash = "sha256:66ff4a3b82b9399dbeacdf5516698406fbdcb5b654b64fec584b185514181c79", size = 33719, upload-time = "2025-08-05T12:03:15.292Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/db/8c957ebe8caa2d58f0df985e2ed10dd0d9d096fb6ca2eedb32f2228c66c3/mkdocs_spellcheck-1.1.2-py3-none-any.whl", hash = "sha256:947644eb2b9b8c06740d7f693838edca1fa195b198c455337648977c9a86f039", size = 13643, upload-time = "2025-08-05T12:03:13.828Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/33/9611380c2bdb1225fdef633e2a9610622310fed35ab11dac9620972ee088/platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312", size = 21632, upload-time = "2025-10-08T17:44:48.791Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/cb/ac7874b3e5d58441674fb70742e6c374b28b0c7cb988d37d991cde47166c/platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3", size = 18651, upload-time = "2025-10-08T17:44:47.223Z" }, +] + +[[package]] +name = "pycodestyle" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pyflakes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58", size = 64669, upload-time = "2025-06-20T18:45:27.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, +] + +[[package]] +name = "pygithub" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyjwt", extra = ["crypto"] }, + { name = "pynacl" }, + { name = "requests" }, + { name = "typing-extensions" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c1/74/e560bdeffea72ecb26cff27f0fad548bbff5ecc51d6a155311ea7f9e4c4c/pygithub-2.8.1.tar.gz", hash = "sha256:341b7c78521cb07324ff670afd1baa2bf5c286f8d9fd302c1798ba594a5400c9", size = 2246994, upload-time = "2025-09-02T17:41:54.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/ba/7049ce39f653f6140aac4beb53a5aaf08b4407b6a3019aae394c1c5244ff/pygithub-2.8.1-py3-none-any.whl", hash = "sha256:23a0a5bca93baef082e03411bf0ce27204c32be8bfa7abc92fe4a3e132936df0", size = 432709, upload-time = "2025-09-02T17:41:52.947Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b3/6d2b3f149bc5413b0a29761c2c5832d8ce904a1d7f621e86616d96f505cc/pymdown_extensions-10.16.1.tar.gz", hash = "sha256:aace82bcccba3efc03e25d584e6a22d27a8e17caa3f4dd9f207e49b787aa9a91", size = 853277, upload-time = "2025-07-28T16:19:34.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/06/43084e6cbd4b3bc0e80f6be743b2e79fbc6eed8de9ad8c629939fa55d972/pymdown_extensions-10.16.1-py3-none-any.whl", hash = "sha256:d6ba157a6c03146a7fb122b2b9a121300056384eafeec9c9f9e584adfdb2a32d", size = 266178, upload-time = "2025-07-28T16:19:31.401Z" }, +] + +[[package]] +name = "pynacl" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/c6/a3124dee667a423f2c637cfd262a54d67d8ccf3e160f3c50f622a85b7723/pynacl-1.6.0.tar.gz", hash = "sha256:cb36deafe6e2bce3b286e5d1f3e1c246e0ccdb8808ddb4550bb2792f2df298f2", size = 3505641, upload-time = "2025-09-10T23:39:22.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/24/1b639176401255605ba7c2b93a7b1eb1e379e0710eca62613633eb204201/pynacl-1.6.0-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:f46386c24a65383a9081d68e9c2de909b1834ec74ff3013271f1bca9c2d233eb", size = 384141, upload-time = "2025-09-10T23:38:28.675Z" }, + { url = "https://files.pythonhosted.org/packages/5e/7b/874efdf57d6bf172db0df111b479a553c3d9e8bb4f1f69eb3ffff772d6e8/pynacl-1.6.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:dea103a1afcbc333bc0e992e64233d360d393d1e63d0bc88554f572365664348", size = 808132, upload-time = "2025-09-10T23:38:38.995Z" }, + { url = "https://files.pythonhosted.org/packages/f3/61/9b53f5913f3b75ac3d53170cdb897101b2b98afc76f4d9d3c8de5aa3ac05/pynacl-1.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:04f20784083014e265ad58c1b2dd562c3e35864b5394a14ab54f5d150ee9e53e", size = 1407253, upload-time = "2025-09-10T23:38:40.492Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0a/b138916b22bbf03a1bdbafecec37d714e7489dd7bcaf80cd17852f8b67be/pynacl-1.6.0-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bbcc4452a1eb10cd5217318c822fde4be279c9de8567f78bad24c773c21254f8", size = 843719, upload-time = "2025-09-10T23:38:30.87Z" }, + { url = "https://files.pythonhosted.org/packages/01/3b/17c368197dfb2c817ce033f94605a47d0cc27901542109e640cef263f0af/pynacl-1.6.0-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51fed9fe1bec9e7ff9af31cd0abba179d0e984a2960c77e8e5292c7e9b7f7b5d", size = 1445441, upload-time = "2025-09-10T23:38:33.078Z" }, + { url = "https://files.pythonhosted.org/packages/35/3c/f79b185365ab9be80cd3cd01dacf30bf5895f9b7b001e683b369e0bb6d3d/pynacl-1.6.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:10d755cf2a455d8c0f8c767a43d68f24d163b8fe93ccfaabfa7bafd26be58d73", size = 825691, upload-time = "2025-09-10T23:38:34.832Z" }, + { url = "https://files.pythonhosted.org/packages/f7/1f/8b37d25e95b8f2a434a19499a601d4d272b9839ab8c32f6b0fc1e40c383f/pynacl-1.6.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:536703b8f90e911294831a7fbcd0c062b837f3ccaa923d92a6254e11178aaf42", size = 1410726, upload-time = "2025-09-10T23:38:36.893Z" }, + { url = "https://files.pythonhosted.org/packages/bd/93/5a4a4cf9913014f83d615ad6a2df9187330f764f606246b3a744c0788c03/pynacl-1.6.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6b08eab48c9669d515a344fb0ef27e2cbde847721e34bba94a343baa0f33f1f4", size = 801035, upload-time = "2025-09-10T23:38:42.109Z" }, + { url = "https://files.pythonhosted.org/packages/bf/60/40da6b0fe6a4d5fd88f608389eb1df06492ba2edca93fca0b3bebff9b948/pynacl-1.6.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5789f016e08e5606803161ba24de01b5a345d24590a80323379fc4408832d290", size = 1371854, upload-time = "2025-09-10T23:38:44.16Z" }, + { url = "https://files.pythonhosted.org/packages/44/b2/37ac1d65008f824cba6b5bf68d18b76d97d0f62d7a032367ea69d4a187c8/pynacl-1.6.0-cp314-cp314t-win32.whl", hash = "sha256:4853c154dc16ea12f8f3ee4b7e763331876316cc3a9f06aeedf39bcdca8f9995", size = 230345, upload-time = "2025-09-10T23:38:48.276Z" }, + { url = "https://files.pythonhosted.org/packages/f4/5a/9234b7b45af890d02ebee9aae41859b9b5f15fb4a5a56d88e3b4d1659834/pynacl-1.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:347dcddce0b4d83ed3f32fd00379c83c425abee5a9d2cd0a2c84871334eaff64", size = 243103, upload-time = "2025-09-10T23:38:45.503Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2c/c1a0f19d720ab0af3bc4241af2bdf4d813c3ecdcb96392b5e1ddf2d8f24f/pynacl-1.6.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2d6cd56ce4998cb66a6c112fda7b1fdce5266c9f05044fa72972613bef376d15", size = 187778, upload-time = "2025-09-10T23:38:46.731Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/87c72df19857c5b3b47ace6f211a26eb862ada495cc96daa372d96048fca/pynacl-1.6.0-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:f4b3824920e206b4f52abd7de621ea7a44fd3cb5c8daceb7c3612345dfc54f2e", size = 382610, upload-time = "2025-09-10T23:38:49.459Z" }, + { url = "https://files.pythonhosted.org/packages/0c/64/3ce958a5817fd3cc6df4ec14441c43fd9854405668d73babccf77f9597a3/pynacl-1.6.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:16dd347cdc8ae0b0f6187a2608c0af1c8b7ecbbe6b4a06bff8253c192f696990", size = 798744, upload-time = "2025-09-10T23:38:58.531Z" }, + { url = "https://files.pythonhosted.org/packages/e4/8a/3f0dd297a0a33fa3739c255feebd0206bb1df0b44c52fbe2caf8e8bc4425/pynacl-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:16c60daceee88d04f8d41d0a4004a7ed8d9a5126b997efd2933e08e93a3bd850", size = 1397879, upload-time = "2025-09-10T23:39:00.44Z" }, + { url = "https://files.pythonhosted.org/packages/41/94/028ff0434a69448f61348d50d2c147dda51aabdd4fbc93ec61343332174d/pynacl-1.6.0-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25720bad35dfac34a2bcdd61d9e08d6bfc6041bebc7751d9c9f2446cf1e77d64", size = 833907, upload-time = "2025-09-10T23:38:50.936Z" }, + { url = "https://files.pythonhosted.org/packages/52/bc/a5cff7f8c30d5f4c26a07dfb0bcda1176ab8b2de86dda3106c00a02ad787/pynacl-1.6.0-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8bfaa0a28a1ab718bad6239979a5a57a8d1506d0caf2fba17e524dbb409441cf", size = 1436649, upload-time = "2025-09-10T23:38:52.783Z" }, + { url = "https://files.pythonhosted.org/packages/7a/20/c397be374fd5d84295046e398de4ba5f0722dc14450f65db76a43c121471/pynacl-1.6.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:ef214b90556bb46a485b7da8258e59204c244b1b5b576fb71848819b468c44a7", size = 817142, upload-time = "2025-09-10T23:38:54.4Z" }, + { url = "https://files.pythonhosted.org/packages/12/30/5efcef3406940cda75296c6d884090b8a9aad2dcc0c304daebb5ae99fb4a/pynacl-1.6.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:49c336dd80ea54780bcff6a03ee1a476be1612423010472e60af83452aa0f442", size = 1401794, upload-time = "2025-09-10T23:38:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/be/e1/a8fe1248cc17ccb03b676d80fa90763760a6d1247da434844ea388d0816c/pynacl-1.6.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:f3482abf0f9815e7246d461fab597aa179b7524628a4bc36f86a7dc418d2608d", size = 772161, upload-time = "2025-09-10T23:39:01.93Z" }, + { url = "https://files.pythonhosted.org/packages/a3/76/8a62702fb657d6d9104ce13449db221a345665d05e6a3fdefb5a7cafd2ad/pynacl-1.6.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:140373378e34a1f6977e573033d1dd1de88d2a5d90ec6958c9485b2fd9f3eb90", size = 1370720, upload-time = "2025-09-10T23:39:03.531Z" }, + { url = "https://files.pythonhosted.org/packages/6d/38/9e9e9b777a1c4c8204053733e1a0269672c0bd40852908c9ad6b6eaba82c/pynacl-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6b393bc5e5a0eb86bb85b533deb2d2c815666665f840a09e0aa3362bb6088736", size = 791252, upload-time = "2025-09-10T23:39:05.058Z" }, + { url = "https://files.pythonhosted.org/packages/63/ef/d972ce3d92ae05c9091363cf185e8646933f91c376e97b8be79ea6e96c22/pynacl-1.6.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4a25cfede801f01e54179b8ff9514bd7b5944da560b7040939732d1804d25419", size = 1362910, upload-time = "2025-09-10T23:39:06.924Z" }, + { url = "https://files.pythonhosted.org/packages/35/2c/ee0b373a1861f66a7ca8bdb999331525615061320dd628527a50ba8e8a60/pynacl-1.6.0-cp38-abi3-win32.whl", hash = "sha256:dcdeb41c22ff3c66eef5e63049abf7639e0db4edee57ba70531fc1b6b133185d", size = 226461, upload-time = "2025-09-10T23:39:11.894Z" }, + { url = "https://files.pythonhosted.org/packages/75/f7/41b6c0b9dd9970173b6acc026bab7b4c187e4e5beef2756d419ad65482da/pynacl-1.6.0-cp38-abi3-win_amd64.whl", hash = "sha256:cf831615cc16ba324240de79d925eacae8265b7691412ac6b24221db157f6bd1", size = 238802, upload-time = "2025-09-10T23:39:08.966Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0f/462326910c6172fa2c6ed07922b22ffc8e77432b3affffd9e18f444dbfbb/pynacl-1.6.0-cp38-abi3-win_arm64.whl", hash = "sha256:84709cea8f888e618c21ed9a0efdb1a59cc63141c403db8bf56c469b71ad56f2", size = 183846, upload-time = "2025-09-10T23:39:10.552Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "selectolax" +version = "0.3.29" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/b9/b5a23e29d5e54c590eaad18bdbb1ced13b869b111e03d12ee0ae9eecf9b8/selectolax-0.3.29.tar.gz", hash = "sha256:28696fa4581765c705e15d05dfba464334f5f9bcb3eac9f25045f815aec6fbc1", size = 4691626, upload-time = "2025-04-30T15:17:37.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/ac/ca4332eecc19124782f6f0d7cb28c331da2e9d9cf25287ba2b3b6a00cea1/selectolax-0.3.29-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:6d3f373efd1db18ac9b2222de2668aaa366a1f0b560241eab128f3ca68e8add1", size = 3656166, upload-time = "2025-04-30T15:16:19.907Z" }, + { url = "https://files.pythonhosted.org/packages/b8/46/2dcae03a94f80f3e0d339c149de8110b5abe1230668b015fd338d9e71a27/selectolax-0.3.29-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:97b9971bb37b54ef4440134f22792d15c9ee12d890a526a7fe0b376502240143", size = 2095991, upload-time = "2025-04-30T15:16:21.654Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bd/95f15396e5f30898227d84a7ec6a39d9a9b34005f0e9f8f38e7fee21ab66/selectolax-0.3.29-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd99ff0f5a6c017c471635d4ee45b61d25f24689331e407147b2cf5e36892480", size = 5844493, upload-time = "2025-04-30T15:16:23.268Z" }, + { url = "https://files.pythonhosted.org/packages/36/25/64c60da9aec81f2992355b0a3ce00ea1ed99e6f5499868016d6972bd4948/selectolax-0.3.29-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8377c317bf1d5fd6ccc56dfb5a0928bbcbea3e800b7af54761cfbbb99dc94cb9", size = 5881062, upload-time = "2025-04-30T15:16:24.891Z" }, + { url = "https://files.pythonhosted.org/packages/b6/81/94105217f91f7c6a98ac3164210cba0c6aa8da91cb85405292a6d70e39c3/selectolax-0.3.29-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5388c56456272b2c241fc1906db9cc993984cafdad936cb5e061e3af0c44144e", size = 5470368, upload-time = "2025-04-30T15:16:26.457Z" }, + { url = "https://files.pythonhosted.org/packages/51/6e/40bc259f13e5d3dd0bb8ddd1d55ef099244db2568ffb82fd9d489984d61a/selectolax-0.3.29-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9e4690894f406863e25ba49da27e1a6fda9bfc21b0b315c399d3093be080e81", size = 5693476, upload-time = "2025-04-30T15:16:28.386Z" }, + { url = "https://files.pythonhosted.org/packages/58/bd/2668ee1d5471ad88daf83ca484515ba46774fc9c951d6c4c0beffea89952/selectolax-0.3.29-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:deeab93386b6c9a75052515f5b9e7e3dd623c585871c0c2b3126970ff902603b", size = 5449747, upload-time = "2025-04-30T15:16:30.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/b5/1c61839ae5af70a8291c643982a99f051b543df90b220b98db1b26bd4899/selectolax-0.3.29-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6abdd8357f1c105c1add01a9f0373511fa832548b2e2778b00a8ba2a4508d6ed", size = 5786843, upload-time = "2025-04-30T15:16:32.231Z" }, + { url = "https://files.pythonhosted.org/packages/67/08/ca42c100ab90168c123e6b521e38cb7618b697a693fdb77e42dabb0670fd/selectolax-0.3.29-cp312-cp312-win32.whl", hash = "sha256:9c969626b2295702076f50aac91e44c3bba639fa2e1a612bf6ae254bf29b4d57", size = 1697859, upload-time = "2025-04-30T15:16:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/5c/22/9524af51d950cc718bd4406f3bed05acbfcb321a4a308ec85b96ccdaa1ef/selectolax-0.3.29-cp312-cp312-win_amd64.whl", hash = "sha256:e7f4cc1b7ce9691559decfd5db7cc500e71a9f6ccfe76c054f284c184a1d1dc9", size = 1804145, upload-time = "2025-04-30T15:16:35.12Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a7/083a00aa9cb6bef0317baba4269841c366652558d77189275bed2da6aa81/selectolax-0.3.29-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e3112f05a34bf36d36ecc51520b1d98c4667b54a3f123dffef5072273e89a360", size = 3651407, upload-time = "2025-04-30T15:16:37.282Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cd/6c89ac27961ef5f5e9b40eda0d0653b9c95c93485fb8a554bf093eac1c77/selectolax-0.3.29-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:38462ae369897f71da287f1282079c11f1b878b99a4d1d509d1116ce05226d88", size = 2092649, upload-time = "2025-04-30T15:16:38.817Z" }, + { url = "https://files.pythonhosted.org/packages/3e/12/82710124b7b52613fdb9d5c14494a41785eb83e1c93ec7e1d1814c2ce292/selectolax-0.3.29-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdd1e63735f2fb8485fb6b9f4fe30d6c030930f438f46a4a62bd9886ab3c7fd9", size = 5821738, upload-time = "2025-04-30T15:16:40.747Z" }, + { url = "https://files.pythonhosted.org/packages/8b/08/8ceb3eb7fee9743026a4481fccb771f257c82b2c853a1a30271902234eab/selectolax-0.3.29-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea52e0c128e8e89f98ab0ccaabbc853677de5730729a3351da595976131b66e0", size = 5856069, upload-time = "2025-04-30T15:16:42.496Z" }, + { url = "https://files.pythonhosted.org/packages/47/6c/ec2b7aff0f6202e4157415d76bd588108cc518374bf53afa81c122691780/selectolax-0.3.29-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0933659b4250b91317ccd78167e6804389cdaf7ed86c5d034b058a550d23110f", size = 5443255, upload-time = "2025-04-30T15:16:44.083Z" }, + { url = "https://files.pythonhosted.org/packages/cd/90/d5fea46ff191d02c2380a779b119ea6799751b79fcddb2bb230b21b38fc5/selectolax-0.3.29-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0c9005e9089a6b0c6fb6a9f691ddbbb10a3a23ebeff54393980340f3dbcdb99", size = 5637529, upload-time = "2025-04-30T15:16:46.175Z" }, + { url = "https://files.pythonhosted.org/packages/9d/83/7f876a515f5af31f7b948cf10951be896fe6deeff2b9b713640c8ec82fd3/selectolax-0.3.29-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac940963c52f13cdf5d7266a979744949b660d367ce669efa073b557f6e09a18", size = 5379121, upload-time = "2025-04-30T15:16:47.909Z" }, + { url = "https://files.pythonhosted.org/packages/57/cb/7dc739a484b1a17ccf92a23dfe558ae615c232bd81e78a72049c25d1ff66/selectolax-0.3.29-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:484274f73839f9a143f4c13ce1b0a0123b5d64be22f967a1dc202a9a78687d67", size = 5727944, upload-time = "2025-04-30T15:16:49.52Z" }, + { url = "https://files.pythonhosted.org/packages/b7/09/95da4d2919d99a6090327390b84bc5440133196351e5e04c24cccda06cbb/selectolax-0.3.29-cp313-cp313-win32.whl", hash = "sha256:29e71fbd58b90d2920ef91a940680cb5331710fe397925ce9d10c3f2f086bf27", size = 1697529, upload-time = "2025-04-30T15:16:51.123Z" }, + { url = "https://files.pythonhosted.org/packages/0e/17/5a3951da22a4ad8f959088ddc370c68b28dad03190d91fcd137a52410fb9/selectolax-0.3.29-cp313-cp313-win_amd64.whl", hash = "sha256:e13befacff5f78102aa11465055ecb6d4b35f89663e36f271f2b506bcab14112", size = 1803334, upload-time = "2025-04-30T15:16:53.775Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +] + +[[package]] +name = "wcmatch" +version = "10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bracex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/3e/c0bdc27cf06f4e47680bd5803a07cb3dfd17de84cde92dd217dcb9e05253/wcmatch-10.1.tar.gz", hash = "sha256:f11f94208c8c8484a16f4f48638a85d771d9513f4ab3f37595978801cb9465af", size = 117421, upload-time = "2025-06-22T19:14:02.49Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/d8/0d1d2e9d3fabcf5d6840362adcf05f8cf3cd06a73358140c3a97189238ae/wcmatch-10.1-py3-none-any.whl", hash = "sha256:5848ace7dbb0476e5e55ab63c6bbd529745089343427caa5537f230cc01beb8a", size = 39854, upload-time = "2025-06-22T19:14:00.978Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] From 4e00f9d794241a9c00a9ef60c8400f74e9f6d99b Mon Sep 17 00:00:00 2001 From: Bob Clough Date: Mon, 13 Oct 2025 17:11:18 +0100 Subject: [PATCH 5/5] :D --- .github/workflows/CI.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 1f47471..39fbed1 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -29,7 +29,7 @@ jobs: - name: Build docs env: CI: ${{ github.ref == 'refs/heads/main' }} - run: pipenv run mkdocs build + run: uv run mkdocs build - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 with: @@ -48,4 +48,3 @@ jobs: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 -