diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0030e84f4fb77dc6f56300fba5c091914e958374 --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +.env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +test-output.html + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# virtualenv +venv/ +ENV/ + +# MkDocs documentation +site/ + +# Mac files +.DS_Store + +# PyCharm ide +.idea + +**/*.ipynb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24d8fc80243d7d26841f02869b645ca6dab277b3..4bb18598456aad496dead6aac949d60fc9e23969 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,37 +1,54 @@ -image: python:slim +image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim + +before_script: + - uv sync + +cache: + paths: + - .cache/pip + - .venv/ + stages: + - test - build - deploy +test_examples: + stage: test + script: + - uv run nox --sessions Test\ Examples + +lint_generation: + stage: test + script: + - uv run nox --sessions Lint\ Code + +test_generation: + stage: test + script: + - uv run nox --sessions Test\ Schema\ Generation + build: stage: build + before_script: - apt update - - apt install -y python3-cffi python3-brotli libpango-1.0-0 libharfbuzz0b libpangoft2-1.0-0 pango1.0-tools - - python3 --version - - pango-view --version - - pip install weasyprint - - pip install mkdocs - - pip install mkdocs-macros-plugin - - pip install mkdocs-material - - pip install mkdocs-build-plantuml-plugin - - pip install mkdocs-with-pdf + - apt install git -y script: - - mkdocs build --site-dir public - artifacts: - paths: - - public + - uv run mkdocs build pages: stage: deploy - dependencies: - - build + + variables: + PROD_ENV: "1" + + before_script: + - apt update + - apt install git -y script: - - echo "Skip script section" - artifacts: - paths: - - public + - uv run mkdocs build -d public only: - master diff --git a/README.md b/README.md index 6ba5ed16950432838ae93a82644187df8934d70f..d188ae60fa5391c0cecb1f0efbd74ddddac9cac5 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,47 @@ -> **Preamble:** We strive to make marine image data [FAIR](docs/FAIR-marine-images.md). We maintain [metadata profiles](docs/ifdos/iFDO-overview.md) to establish a common language of marine imagery, we develop best-practice [operating procedures](docs/sops/sop-overview.md) for handling marine images and we develop [software tools](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/) to apply the vocabulary and procedures to marine imagery. +# FAIR marine images +> We strive to make marine image data [FAIR](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/FAIR-marine-images/). We maintain the iFDO +> [metadata vocabulary](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/overview/iFDO-overview/) to establish a common language for describing marine imagery, we provide +> [metadata schemas](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/standard/v2.1.0/schema/ifdo.json) to link the iFDO format to established metadata +> standards, we develop best-practice [standard operating procedures](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/sops/sop-overview.md) for handling marine images, and we +> implement [software tools](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/) to apply the vocabulary and procedures to marine imagery. -# Journal publication -The principles and workflows - described on these pages here - in detail have been published as a peer-reviewed journal article in Nature Scientific Data: https://doi.org/10.1038/s41597-022-01491-3 +## How do I get started using iFDOs? +1. Read this documentation to [explore the metadata fields](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/overview/iFDO-overview/) that are required or constrained +2. Install a software that understands the iFDO concept (e.g. mariqt) +3. Look at [example iFDO](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/standard/v2.1.0/examples/ifdo-image-example.json) files +4. Collect your own image metadata, maybe by using the provided [Excel sheets](https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/resources/sheets/Overview-iFDO-metadata-collection.xlsx) +## Where are the details? +The principles and workflows - described on these pages here - have been published in detail as a peer-reviewed +journal article in Nature Scientific Data: https://doi.org/10.1038/s41597-022-01491-3 Please cite this article in your own works in case you use iFDOs for your data. -# Overview -This repository contains documentation on how to make (marine) image data FAIR (and open). You have three options to browse the information: -- https://datahub.pages.hzdr.de/marehub/ag-videosimages/fair-marine-images/ (pretty, protected, up-to-date) -- https://marine-imaging.com/fair (pretty, public, not up-to-date) -- use this repository (not pretty, but public and up-to-date) - -# Resources for download -- [Excel sheet](resources/iFDO.xlsx) to collect metadata information for [iFDOs](docs/ifdos/iFDO-overview.md) -- [Example iFDO core](resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_core.yaml) -- [Example iFDO capture](resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_capture.yaml) -- [Example iFDO content](resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_content.yaml) -- [Allowed terms](resources/MareHub_AGVI_iFDO_capture-vocabulary.yaml) of [iFDO capture](docs/ifdos/iFDO-capture.md) fields +## How to contribute? + +### Building the page locally +This project uses the package manager [uv](https://docs.astral.sh/uv/) +```shell +git clone git@codebase.helmholtz.cloud:datahub/marehub/ag-videosimages/fair-marine-images.git +cd fair-marine-images + +uv sync +``` +This creates a virtual environment in `fair-marine-images/.venv/`. + +The page is build into `fair-marine-images/site/` by invoking [mkdocs](https://www.mkdocs.org) +```shell +uv run mkdocs build +``` +For more build options see the [mkdocs build](https://www.mkdocs.org/user-guide/cli/#mkdocs-build) documentation. + +Mkdocs also provides a development server, which can be started by running +```shell +uv run mkdocs serve +``` +For more options see the [mkdocs serve](https://www.mkdocs.org/user-guide/cli/#mkdocs-serve) documentation. + +If you want to contribute to the standard or documentation you can run +```shell +uv run nox +``` +before submitting your changes, to ensure the correctness of the standard and documentation. \ No newline at end of file diff --git a/docs/FAIR-marine-images.md b/docs/FAIR-marine-images.md index 0cef1fba3a9383579f444bddbe7d2a176c194444..9e4a4cc119f9f9220863e48a13b72f796077ca57 100644 --- a/docs/FAIR-marine-images.md +++ b/docs/FAIR-marine-images.md @@ -7,50 +7,52 @@ Curiously, FAIR does not necessarily mean open. So while - in theory - your data ## FAIRness of marine images What FAIR means and is and how to become FAIR is an active field of research. There are vast amounts of information available: e.g. by the [EOSC](https://eosc-portal.eu/) (European Open Science Could) or the [RDA](https://rd-alliance.org/) (Research Data Alliance). Their working groups produce fantastic implementation guidelines for users, managers, governing agencies etc. including ones on _Metrics to assess FAIRness_ (by EOSC: [Recommendations on FAIR metrics](https://doi.org/10.2777/70791), by RDA: [FAIR Data Maturity Model](https://doi.org/10.15497/rda00050)). -The following table applies these metrics to marine images to track our status at achieving our goal: to make marine images FAIR. +The following table shows how these metrics relate to marine images and how the iFDO concept and the developed FAIR +marine image infrastructure address these metrics to achieve our goal: to make marine images FAIR. | [FAIR principle](https://www.go-fair.org/fair-principles/) | [FAIR Metrics ID](https://doi.org/10.2777/70791) | Indicator | Priority | Marine images | | - | - | - | - | - | -| F1 | RDA-F1-01M | Metadata is identified by a persistend identifier | Essential | [ ] Handle -| F1 | RDA-F1-01D | Data is identified by a persistent identifier | Essential | [ ] Handle | - | F1 | RDA-F1-02M | Metadata is identified by a globally unique identifier | Essential | [x] UUID | - | F1 | RDA-F1-02D | Data is identified by a globally unique identifier | Essential | [x] UUID | - | F2 | RDA-F2-01M | Rich metadata is provided to allow discovery | Essential | [x] [iFDO](ifdos/iFDO-overview.md) | - | F3 | RDA-F3-01M | Metadata includes the indentifier for the data | Essential | [x] iFDO | - | F4 | RDA-F4-01M | Metadata is offered in such a way that it can be harvested and indexed | Essential | [ ] OSIS-API | - | A1 | RDA-A1-01M | Metadata contains information to enable the user to get access to the data | Important | [x] iFDO | - | A1 | RDA-A1-02M | Metadata can be accessed manually | Essential | [x] [OSIS-www](https://osis.geomar.de/app) | - | A1 | RDA-A1-02D | Data can be accessed manually | Essential | [x] Elements | - | A1 | RDA-A1-03M | Metadata identifier resolves to a metadata record | Essential | [x] iFDO | - | A1 | RDA-A1-03D | Data identifiert resolves to a digital object | Essential | [x] iFDO | - | A1 | RDA-A1-04M | Metadata is acccessed through standardised protocol | Essential | [x] https | - | A1 | RDA-A1-04D | Data is accessible through standardised protocol | Essential | [x] https | - | A1 | RDA-A1-05D | Data can be accessed automatically | Important | [x] Elements-API | - | A1.1 | RDA-A1.1-01M | Metadata is accessible through a free access protocol | Essential | [x] https | - | A1.1 | RDA-A1.1-01D | Data is accessible through a free access protocol | Important | [x] https | - | A1.2 | RDA-A1.2-01D | Data is accessible through an access protocol that supports authentication and authorisation | Useful | [ ] _No_ | - | A2 | RDA-A2-01M | Metadata is guaranteed to remain available after data is no longer available | Essential | [x] Yes | - | I1 | RDA-I1-01M | Metadata uses knowledge representation expressed in standardised format | Important | [x] [iFDO](ifdos/iFDO-overview.md) | - | I1 | RDA-I1-01D | Data uses knowledge representation expressed in standardised format | Important | [x] jpg, tif, png | - | I1 | RDA-I1-02M | Metadata uses machine-understandable knowledge representation | Important | [x] FDO | - | I1 | RDA-I1-02D | Data uses machine-understandable knowledge representation | Important | [x] jpg, tif, png | - | I2 | RDA-I2-01M | Metadata uses FAIR-compliant vocabularies | Important | [ ] MVP Git? | - | I2 | RDA-I2-01D | Data uses FAIR-compliant vocabularies | Useful | [x] MVP Git | - | I3 | RDA-I3-01M | Metadata includes references to other metadata | Important | [x] Orcid, URN | - | I3 | RDA-I3-01D | Data includes references to other data | Useful | [ ] _No_ | - | I3 | RDA-I3-02M | Metadata includes refereces to other data | Useful | [ ] _No_ | - | I3 | RDA-I3-02D | Data includes qualified references to other data | Useful | [ ] _No_ | - | I3 | RDA-I3-03M | Metadata includes qualified references to other metadata | Important | [ ] **No** | - | I3 | RDA-I3-04M | Metadata includes qualified references to other data | Useful | [ ] _No_ | - | R1 | RDA-R1-01M | Plurality of accurate and relevant attributes are provided to allow reuse | Essential | [x] iFDO | - | R1.1 | RDA-R1.1-01M | Metadata includes information about the license under which the data can be reused | Essential | [x] iFDO | - | R1.1 | RDA-R1.1-02M | Metadata refers to a standard reuse license | Important | [x] iFDO | - | R1.1 | RDA-R1.1-03M | Metadata refers to a machine-understandable reuse license | Important | [x] iFDO | - | R1.2 | RDA-R1.2-01M | Metadata includes provenance information according to community-specific standards | Important | [ ] **No** | - | R1.2 | RDA-R1.2-02M | Metadata includes provenance information according to a cross-community language | Useful | [ ] _No_ | - | R1.3 | RDA-R1.3-01M | Metadata complies with a community standard | Essential | [x] MVP | - | R1.3 | RDA-R1.3-01D | Data complies with a communty standard | Essential | [x] MVP | - | R1.3 | RDA-R1.3-03M | Metadata is expressed in compliance with a machine-understanable community standard | Essential | [x] MVP | - | R1.3 | RDA-R1.3-02D | Data is expressed incompliance with a machine-understandable community standard | Important | **No** | +| F1 | RDA-F1-01M | Metadata is identified by a persistent identifier | Essential | [x] image-set-handle@ifdo | +| F1 | RDA-F1-01D | Data is identified by a persistent identifier | Essential | [x] image-set-handle@data | +| F1 | RDA-F1-02M | Metadata is identified by a globally unique identifier | Essential | [x] image-set-uuid | +| F1 | RDA-F1-02D | Data is identified by a globally unique identifier | Essential | [x] image-set-uuid | +| F2 | RDA-F2-01M | Rich metadata is provided to allow discovery | Essential | [x] [iFDO](overview/iFDO-overview.md) | +| F3 | RDA-F3-01M | Metadata includes the identifier for the data | Essential | [x] image-set-uuid | +| F4 | RDA-F4-01M | Metadata is offered in such a way that it can be harvested and indexed | Essential | [ ] OAI-PMH | +| A1 | RDA-A1-01M | Metadata contains information to enable the user to get access to the data | Important | [x] image-set-handle@data | +| A1 | RDA-A1-02M | Metadata can be accessed manually | Essential | [x] image-set-handle@ifdo | +| A1 | RDA-A1-02D | Data can be accessed manually | Essential | [x] image-set-handle@data | +| A1 | RDA-A1-03M | Metadata identifier resolves to a metadata record | Essential | [x] image-set-handle@ifdo | +| A1 | RDA-A1-03D | Data identifier resolves to a digital object | Essential | [x] image-handle | +| A1 | RDA-A1-04M | Metadata is accessed through standardised protocol | Essential | [x] https | +| A1 | RDA-A1-04D | Data is accessible through standardised protocol | Essential | [x] https | +| A1 | RDA-A1-05D | Data can be accessed automatically | Important | [x] ImageBroker API | +| A1.1 | RDA-A1.1-01M | Metadata is accessible through a free access protocol | Essential | [x] https | +| A1.1 | RDA-A1.1-01D | Data is accessible through a free access protocol | Important | [x] https | +| A1.2 | RDA-A1.2-01D | Data is accessible through an access protocol that supports authentication and authorisation | Useful | [ ] _No_ | +| A2 | RDA-A2-01M | Metadata is guaranteed to remain available after data is no longer available | Essential | [x] Yes | +| I1 | RDA-I1-01M | Metadata uses knowledge representation expressed in standardised format | Important | [x] [iFDO](overview/iFDO-overview.md) | +| I1 | RDA-I1-01D | Data uses knowledge representation expressed in standardised format | Important | [x] jpg, tif, png | +| I1 | RDA-I1-02M | Metadata uses machine-understandable knowledge representation | Important | [x] iFDO | +| I1 | RDA-I1-02D | Data uses machine-understandable knowledge representation | Important | [x] jpg, tif, png | +| I2 | RDA-I2-01M | Metadata uses FAIR-compliant vocabularies | Important | [ ] iFDO schema | +| I2 | RDA-I2-01D | Data uses FAIR-compliant vocabularies | Useful | [ ] No | +| I3 | RDA-I3-01M | Metadata includes references to other metadata | Important | [x] e.g. image-pi | +| I3 | RDA-I3-01D | Data includes references to other data | Useful | [ ] _No_ | +| I3 | RDA-I3-02M | Metadata includes references to other data | Useful | [x] image-related-material | +| I3 | RDA-I3-02D | Data includes qualified references to other data | Useful | [ ] _No_ | +| I3 | RDA-I3-03M | Metadata includes qualified references to other metadata | Important | [x] e.g. image-pi:uri | +| I3 | RDA-I3-04M | Metadata includes qualified references to other data | Useful | [x] image-related-material | +| R1 | RDA-R1-01M | Plurality of accurate and relevant attributes are provided to allow reuse | Essential | [x] iFDO | +| R1.1 | RDA-R1.1-01M | Metadata includes information about the license under which the data can be reused | Essential | [x] image-license | +| R1.1 | RDA-R1.1-02M | Metadata refers to a standard reuse license | Important | [x] image-license | +| R1.1 | RDA-R1.1-03M | Metadata refers to a machine-understandable reuse license | Important | [x] image-license:uri | +| R1.2 | RDA-R1.2-01M | Metadata includes provenance information according to community-specific standards | Important | [x] image-provenance | +| R1.2 | RDA-R1.2-02M | Metadata includes provenance information according to a cross-community language | Useful | [x] image-provenance / w3-prov | +| R1.3 | RDA-R1.3-01M | Metadata complies with a community standard | Essential | [x] iFDO | +| R1.3 | RDA-R1.3-01D | Data complies with a community standard | Essential | [x] jpg, tif, png | +| R1.3 | RDA-R1.3-03M | Metadata is expressed in compliance with a machine-understandable community standard | Essential | [x] iFDO | +| R1.3 | RDA-R1.3-02D | Data is expressed in compliance with a machine-understandable community standard | Important | iFDO & schema | -_(as of April 2021 - while there are still challenges to overcome, we are close to achieving FAIRness - at least conceptually)_ +_(as of February 2023 - while there are still challenges to overcome, we are close to achieving FAIRness - at least +conceptually)_ diff --git a/resources/logos/ifdo_logo.svg b/docs/assets/ifdo_logo.svg similarity index 100% rename from resources/logos/ifdo_logo.svg rename to docs/assets/ifdo_logo.svg diff --git a/resources/logos/ifdo_logo_grey.svg b/docs/assets/ifdo_logo_grey.svg similarity index 100% rename from resources/logos/ifdo_logo_grey.svg rename to docs/assets/ifdo_logo_grey.svg diff --git a/docs/governance.md b/docs/governance.md new file mode 100644 index 0000000000000000000000000000000000000000..809e29f922b2dee3d6146a8b4152ec1101ae69bf --- /dev/null +++ b/docs/governance.md @@ -0,0 +1,24 @@ +# Governance +Over its first year of existence, the iFDO format was developed by members of the MareHub working group on +Images/Videos and through the Helmholtz-funded project _FDO-5DI_ of DLR and GEOMAR. Additional input was +collected from the international Marine Imaging Community at the Marine Imaging Workshops. + +Everyone is invited to contribute to the further development of the iFDO format. Please submit an issue in the +repository, or email ifdo [at] marine-imaging.com to recommend changes. + +At present, the Marine Imaging Community is setting up an iFDO steering board of members from academia, industry and +governance with international to develop the iFDO roadmap from the community inputs. Please write an e-mail to +ifdo [at] marine-imaging.com in case you are interested in joining this steering board. + +### History of iFDO development + +**v2.1.0:** Should include a mechanism to represent stereo imagery + +**v2.0.0 (current):** Major changes in format and to include missing information provided by the community + +**v1.1.0:** Updated fields and added more detailed, consistent and specific documentation. + +**v1.0.0:** Initial publication of the iFDO concept through the repository at https://gitlab.hzdr. +de/datahub/marehub/ag-videosimages/fair-marine-images and with static supplementary material published as OceanBest Practice (https://hdl.handle.net/11329/1781 and https://hdl.handle.net/11329/1782). + + diff --git a/docs/ifdos/iFDO-capture.md b/docs/ifdos/iFDO-capture.md deleted file mode 100644 index c19b9737ec23bba13c3901f4dbd9396ed6697cd1..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO-capture.md +++ /dev/null @@ -1,86 +0,0 @@ -# iFDO capture section -The iFDO capture is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about its file formats, parts and sections. All fields in this section are optional! - -## Motivation -Information on how image data was captured can be crucial to understand information extracted from the images. It is thus highly recommended to enrich all iFDOs with capture information. The potential metadata in the iFDO capture fields is expected to grow with time, as additional (marine) imaging domains make use of this concept. Anyhow, below you find a pool of iFDO capture fields which are highly recommened to be added to your iFDO. Only with these fields populated will your dataset shine in a marine data portal! - -## File format -All iFDO capture fields shall be stored alongside the core metadata in your iFDO file! It does not take up a specific section of the file, rather the values are intermixed into the image-set-header and image-set-items section! - -# iFDO capture fields - -## ... with restricted values (all to be given as strings) - -| Field | Allowed Values | Comment | -| ----- | -------------- | ------- | -| image-acquisition | photo, video, slide | photo: still images, video: moving images, slide: microscopy images / slide scans | -| image-quality | raw, processed, product | raw: straight from the sensor, processed: QA/QC'd, product: image data ready for interpretation | -| image-deployment | mapping, stationary, survey, exploration, experiment, sampling | mapping: planned path execution along 2-3 spatial axes, stationary: fixed spatial position, survey: planned path execution along free path, exploration: unplanned path execution, experiment: observation of manipulated environment, sampling: ex-situ imaging of samples taken by other method | -| image-navigation | satellite, beacon, transponder, reconstructed | satellite: GPS/Galileo etc., beacon: USBL etc., transponder: LBL etc., reconstructed: position estimated from other measures like cable length and course over ground | -| image-scale-reference | 3D camera, calibrated camera, laser marker, optical flow | 3D camera: the imaging system provides scale directly, calibrated camera: image data and additional external data like object distance provide scale together, laser marker: scale information is embedded in the visual data, optical flow: scale is computed from the relative movement of the images and the camera navigation data | -| image-illumination | sunlight, artificial light, mixed light | sunlight: the scene is only illuminated by the sun, artificial light: the scene is only illuminated by artificial light, mixed light: both sunlight and artificial light illuminate the scene | -| image-pixel-magnitude | km, hm, dam, m, cm, mm, µm | average size of one pixel of an image | -| image-marine-zone | seafloor, water column, sea surface, atmosphere, laboratory | seafloor: images taken in/on/right above the seafloor, water column: images taken in the free water without the seafloor or the sea surface in sight, sea surface: images taken right below the sea surface, atmosphere: images taken outside of the water, laboratory: images taken ex-situ | -| image-spectral-resolution | grayscale, rgb, multi-spectral, hyper-spectral | grayscale: single channel imagery, rgb: three channel imagery, multi-spectral: 4-10 channel imagery, hyper-spectral: 10+ channel imagery | -| image-capture-mode | timer,manual,mixed | whether the time points of image capture were systematic, human-truggered or both | -| image-fauna-attraction | none, baited, light | Allowed: none, baited, light | - -By limiting these fields to restricted values, it is possible to classify and filter image data sets in data portals and to visualize data characteristics. See the [iFDO capture icon overview](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/blob/master/docs/ifdos/iFDO-capture-icons.md) for more details - - -## ... with free values - -| Field | Format | Comment | -| ----- | -------------- | ------- | -| image-area-square-meter | float | The footprint of the entire image in square meters | -| image-meters-above-ground | float | Distance of the camera to the seafloor in meters | -| image-acquisition-settings | dict | All the information that is recorded by the camera in the EXIF, IPTC etc. As a dict. Includes ISO, aperture, etc. | -| image-camera-yaw-degrees | float | Camera view yaw angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \'right-hand rule\'. I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north. | -| image-camera-pitch-degrees | float | Camera view pitch angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \'right-hand rule\'. I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north. | -| image-camera-roll-degrees | float | Camera view roll angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \'right-hand rule\'. I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north. | -| image-overlap-fraction | float | The average overlap of two consecutive images i and j as the area images in both of the images (A_i * A_j) divided by the total area images by the two images (A_i + A_j - A_i * A_j): f = A_i * A_j / (A_i + A_j - A_i * A_j) -> 0 if no overlap. 1 if complete overlap | -| image-datetime-format | string | A date time format string in Python notation (e.g. %Y-%m-%d %H:%M:%S.%f) to specify a different date format used throughout the iFDO file. The assumed default is the one in brackets. Make sure to reach second-accuracy with your date times! | -| image-camera-pose | dict | Information required to specify camera pose. For details on subfields see rows below. | -| image-camera-pose:pose-utm-zone | string | The UTM zone number | -| image-camera-pose:pose-utm-epsg | string | The EPSG code of the UTM zone | -| image-camera-pose:pose-utm-east-north-up-meters | [float,float,float] | The position of the camera center in UTM coordinates. | -| image-camera-pose:pose-absolute-orientation-utm-matrix | list | 3x3 row-major float rotation matrix that transforms a direction in camera coordinates (x,y,z = right,down,line of sight) into a direction in UTM coordinates (x,y,z = easting,northing,up)} | -| image-camera-housing-viewport | dict | Information on the camera pressure housing viewport (the glass). For details on subfields see rows below. | -| image-camera-housing-viewport:viewport-type | string | e.g.: flatport, domeport, other | -| image-camera-housing-viewport:viewport-optical-density | float | Unit-less optical density number (1.0=vacuum) | -| image-camera-housing-viewport:viewport-thickness-millimeter | float | Thickness of viewport in millimeters | -| image-camera-housing-viewport:viewport-extra-description | text | A textual description of the viewport used | -| image-flatport-parameters | dict | Information required to specify the characteristics of a flatport camera housing. For details on subfields see rows below. | -| image-flatport-parameters:flatport-lens-port-distance-millimeter | float | The distance between the front of the camera lens and the inner side of the housing viewport in millimeters. | -| image-flatport-parameters:flatport-interface-normal-direction | [float, float, float] | 3D direction vector to specify how the view direction of the lens intersects with the viewport (unit-less, (0,0,1) is "aligned") | -| image-flatport-parameters:flatport-extra-description | text | A textual description of the flatport used | -| image-domeport-parameters | dict | Information required to specify the characteristics of a domeport camera housing. For details on subfields see rows below. | -| image-domeport-parameters:domeport-outer-radius-millimeter | float | Outer radius of the domeport - the part that has contact with the water. | -| image-domeport-parameters:domeport-decentering-offset-xyz-millimeter | [float,float,float] | 3D offset vector of the camera center from the domeport center in millimeters | -| image-domeport-parameters:domeport-extra-description | text | A textual description of the domeport used | -| image-camera-calibration-model | dict | Information required to specify the camera calibration model. For details on the subfields see rows below. | -| image-camera-calibration-model:calibration-model-type | string | e.g.: rectilinear air, rectilinear water, fisheye air, fisheye water, other | -| image-camera-calibration-model:calibration-focal-length-xy-pixel | [float, float] | 2D focal length in pixels | -| image-camera-calibration-model:calibration-principal-point-xy-pixel | [float,float] | 2D principal point of the calibration in pixels (top left pixel center is 0,0, x right, y down) | -| image-camera-calibration-model:calibration-distortion-coefficients | list | rectilinear: k1, k2, p1, p2, k3, k4, k5, k6, fisheye: k1, k2, k3, k4 | -| image-camera-calibration-model:calibration-approximate-field-of-view-water-xy-degree | [float, float] | Proxy for pixel to meter conversion, and as backup | -| image-camera-calibration-model:calibration-model-extra-description | text | Explain model, or if lens parameters are in mm rather than in pixel | -| image-photometric-calibration | dict | Information required to specify the photometric calibration. For details on the subfields see rows below. | -| image-photometric-calibration:photometric-sequence-white-balancing | text | A text on how white-balancing was done. | -| image-photometric-calibration:photometric-exposure-factor-RGB | [float, float, float] | RGB factors applied to this image, product of ISO, exposure time, relative white balance | -| image-photometric-calibration:photometric-sequence-illumination-type | string | e.g. "constant artificial", "globally adapted artificial", "individually varying light sources", "sunlight", "mixed") | -| image-photometric-calibration:photometric-sequence-illumination-description | text | A text on how the image sequence was illuminated | -| image-photometric-calibration:photometric-illumination-factor-RGB | [float, float, float] | RGB factors applied to artificial lights for this image | -| image-photometric-calibration:photometric-water-properties-description | text | A text describing the photometric properties of the water within which the images were capture | -| image-objective | text | A general translation of the aims and objectives of the study, as they pertain to biology and method scope. This should define the primary and secondary data to be measured and to what precision. | -| image-target-environment | text | A description, delineation, and definition of the habitat or environment of study, including boundaries of such | -| image-target-timescale | text | A description, delineation, and definition of the period, interval or temporal environment of the study. | -| image-spatial-contraints | text | A description / definition of the spatial extent of the study area (inside which the photographs were captured), including boundaries and reasons for constraints (e.g. scientific, practical) | -| image-temporal-constraints | text | A description / definition of the temporal extent, including boundaries and reasons for constraints (e.g. scientific, practical) | -| image-time-synchronisation | text | Synchronisation procedure and determined time offsets between camera recording values and UTC | -| image-item-identification-scheme | text | How the images file names are constructed. Should be like this `<project>_<event>_<sensor>_<date>_<time>.<ext>` | -| image-curation-protocol | text | A description of the image and metadata curation steps and results | -| ... and many more to come | | Please suggest more by reporting an issue or creating a merge request! | - -# Examples -[iFDO capture example](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/blob/master/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_capture.yaml) diff --git a/docs/ifdos/iFDO-content.md b/docs/ifdos/iFDO-content.md deleted file mode 100644 index 3a1e04e9e155af78da540a298d98e01944e663d7..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO-content.md +++ /dev/null @@ -1,38 +0,0 @@ -# iFDO content section -The iFDO content is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about its file formats, parts and sections. All fields in this section are optional! - -## Motivation -Image data is inherently unstructured and obtaining a glimpse of its content is hard to achieve for humans as well as machines. The iFDOs content fields are a mechanism to encode the content of image data by means of visual, textual or other data proxies (annotations, previews, descriptions, categorisations, etc.). These can take various forms as described below. Simple examples of visual proxies are thumbnails for images or the average intensity along a video. - -## File format -All iFDO content fields shall be stored alongside the core metadata in your iFDO file! It does not take up a specific section of the file, rather the values are intermixed into the image-set-header and image-set-items section! - -# iFDO content fields - -# Further domain-specific iFDO content fields -| Field | Format | Comment | -| ----- | ------ | ------- | -| image-entropy | float | Information content of an image / frame according to Shannon entropy. | -| image-particle-count | int | Counts of single particles/objects in an image / frame | -| image-average-color | [int,int,int] | The average colour for each image / frame and the `n` channels of an image (e.g. 3 for RGB) | -| image-mpeg7-colorlayout | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.| -| image-mpeg7-colorstatistic | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | -| image-mpeg7-colorstructure | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | -| image-mpeg7-dominantcolor | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | -| image-mpeg7-edgehistogram | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | -| image-mpeg7-homogeneoustexture | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | -| image-mpeg7-scalablecolor | [float,float,...] | An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings. | - -# iFDO content fields for annotations -| Field | Format / Values / Unit | Comment | -| ----- | ---------------------- | ------- | -| image-annotation-labels | [{id:`<LID>`,name:string,info:`<description>`},...] | All the labels used in the image-annotations. Specified by an id (e.g. AphiaID), a human-readable name and an optional description. | -| image-annotation-creators | [{id:`<ORCID/UUID>`,name:string,type:string (expert, non-expert, AI)},...] | All the annotators that created image-annotations. Specified by an id (e.g. ORCID), a human-readable name and an optional type specifying the annotator's expertise. | -| image-annotations | [{coordinates:...,labels:...,shape:,...,frames:...},`<ANNOTATION-2>`,...] | This field is mighty powerful! It stores all annotations as a list of dictionaries of 3-4 fields: shape, coordinates, labels and (optional) frames. See further explanations below. The list of labels specifies the IDs or names of objects and annotators and their confidence. These should be specified in an `image-annotation-labels` and `image-annotation-creators` field (see above) to provide more information on the values used in these fields. | -| image-annotations:shape | single-pixel, polyline, polygon, circle, rectangle, ellipse, whole-image | The annotation shape is specified by a keyword (allowed values: see previous column). | -| image-annotations:coordinates | [[p1.x,p1.y,p2x,p2.y,...]..] | The pixel coordinates of one annotation. The top-left corner of an image is the (0,0) coordinate. The x-axis is the horizontal axis. Pixel coordinates may be fractional. Coordinates can be given as a list of lists in case of video annotations that change coordinates over time (see `image-annotation:frames` below). Otherwise it is just a list of floats. The required number of pixel coordinates is defined by the shape (0 for whole-image, 2 for single-pixel, 3 for circle, 8 for ellipse/rectangle, 4 or more for polyline, 8 or more for polygon). The third coordinate value of a circle defines the radius. The first and last coordinates of a polygon must be equal. | -| image-annotations:labels | [{label: `<LID>`, annotator: `<ORCID/UUID>`, created-at: `<datetime>`, confidence: `<float>`},...] | A list of labels and annotators for one annotation. Use label IDs and annotator IDs here. The optional confidence in an annotation can be given as a float between 0 (100% uncertain) and 1 (100% certain). The confidence can be given independently for each label. Labels are independent of frames. The `created-at` field contains an ISO8601 string like `2011-10-05T14:48:00.000Z` | -| image-annotations:frames | [f1,...] | (only required for video annotations) Frame times (in seconds from the beginning of a video) of a video annotation. Each frame time is linked to one entry in `image-annotations:coordinates` at the same position in the list, which specifies the current coordinates of the annotation at that frame. | - -# Example: -[iFDO content example](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/blob/master/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_content.yaml) diff --git a/docs/ifdos/iFDO-core.md b/docs/ifdos/iFDO-core.md deleted file mode 100644 index 817368224ff114e8d848951f5863adac6cd4a2e3..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO-core.md +++ /dev/null @@ -1,52 +0,0 @@ -# iFDO core -The iFDO core is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about its file formats, parts and sections. All fields in this section are mandatory! - -## Header information in the `image-set-header` part -These three `image-set-header` values have to exist and cannot be superseded by values of the `image-set-items`. Fields from the `image-set-items` part (below) may exist in the header as default values for the entire image set. Bold text shows suggested best-practices. - -| Field | Format / Values / Unit | Comment | -| ----- | ---------------------- | ------- | -| image-set-name | string | A unique name for the image set, should include `<project>, <event>, <sensor>` and purpose | -| image-set-uuid | UUID | A UUID (**version 4 - random**) for the entire image set | -| image-set-handle | string | A Handle URL (using the UUID?) to point to the landing page of the data set | -| image-set-ifdo-version | string | The semantic version information of the iFDO standard used. The default is v1.0.0 | - -In yaml, the entire `image-set-header` part is one dictionary. - -## Image item information in the `image-set-items` part - -| Field | Format | Comment | -| ----- | ---------------------- | ------- | -| image-datetime | string | The fully-qualified ISO8601 UTC time of image acquisition (or start time of a video). E.g.: %Y-%m-%d %H:%M:%S.%f (in Python). You *may* specify a different date format using the optional iFDO capture field `image-datetime-format` | -| image-latitude | float | Y-coordinate of the camera center in decimal degrees: D.DDDDDDD (use at least seven significant digits that is ca. 1cm resolution) | -| image-longitude | float | X-coordinate of the camera center in decimal degrees: D.DDDDDDD (use at least seven significant digits that is ca. 1cm resolution) | -| image-depth | float | Z-coordinate of camera center in meters. *Use this when camera is below water, then it has positive values.* | -| image-altitude | float | Z-coordinate of camera center in meters. *Use this when camera is above water, then it has positive values.* You can also use image-depth with negative values instead! | -| image-coordinate-reference-system | string | The coordinate reference system, e.g. **EPSG:4326** | -| image-coordinate-uncertainty-meters | float | The average/static uncertainty of coordinates in this dataset, given in meters. Computed e.g. as the standard deviation of coordinate corrections during smoothing / splining. | -| image-context | string | The high-level "umbrella" project | -| image-project | string | The lower-level / specific expedition or cruise or experiment or ... | -| image-event | string | One event of a project or expedition or cruise or experiment or ... | -| image-platform | string | Platform URN or Equipment Git ID or Handle URL | -| image-sensor | string | Sensor URN or Equipment Git ID or Handle URL | -| image-uuid | UUID | UUID (**version 4 - random**) for the image file (still or moving) | -| image-hash-sha256 | string | An SHA256 hash to represent the whole file (including UUID in metadata!) to verify integrity on disk | -| image-pi | dict | Information to identify the principal investigator. See details below | -| image-pi:name | string | Full name of principal investigator | -| image-pi:orcid | string | ORCID of principal investigator | -| image-creators | list | A list containing dicts for all creators containing: {orcid:..., name:...} | -| image-license | string | License to use the data (should be FAIR, e.g. **CC-BY** or CC-0) | -| image-copyright | text | Copyright sentence / contact person or office | -| image-abstract | text | 500 - 2000 characters describing what, when, where, why and how the data was collected. Includes general information on the event (aka station, experiment), e.g. overlap between images/frames, parameters on platform movement, aims, purpose of image capture etc. | - -In yaml, the `image-set-items` part is one dictionary. The keys in that dictionary are the filenames of the items in the image set. Each item, indexed by the `image-filename`, is itself a list ob dictionaries. For videos, the first entry of the list contains the default fields for the entire video. Do not repeat static metadata for each second of a video to avoid repetition. Every subsequent entry contains specifications that supersede the default values for one specific time point of the video. For photos (still images) this list has only one entry, containing the fields tabled above or it is no list at all but rather the single dictionary for this photo. - -## UUIDs and hashes -### UUID -Making data FAIR requires - amongst other things - that data is assigned a persistent identifier (PID). Many such PID systems exist, and usually they are based on the handle system (like DOIs for example) and alpha-numerical IDs that are globally unique. For images, we chose to use UUIDs (*Universally Unique Identifiers*), more precisely UUID type 4: random. These UUIDs can be created by anyone and as there are ca 21^36 possible UUID4s making it almost impossible that the same one is created more than once. This UUID is the alphanumerical identifier that has to be assigned to each image and to each image set. That means that the UUID for an image item (a photo or video) *has to become part of the file itself!* You need to write it into the image file's metadata header. How this can be done depends on the image file format you chose but in general the two magnificent software tools *exiftool* anf *ffmpeg* are the solution. In case you are using the MarIQT software, these tools are used under the hood. - -### Hash -We use hashes to document the integrity of the image files. A hash is like a fingerprint of the file as it is computed from the file's byte content. If you like, it is a massive compression of the file's data into a short, cryptic text (ca. 32 characters) but unlike a zip file there is no way to uncompress the file from the hash. Using hashes allows us to make sure that a file has not gone corrupt or that a particular file is actually the version we are interested in. Checking the integrity of a file with hashes requires, that the byte content does not change. It is therefore absolutely essential, that the UUID is written to the image file's metadata header **before** the hash for that file is computed! - -# Example: -[iFDO core example](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/blob/master/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_core.yaml) diff --git a/docs/ifdos/iFDO-icons.md b/docs/ifdos/iFDO-icons.md deleted file mode 100644 index 2daf51671005817e0519918433a3fcc9888f1408..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO-icons.md +++ /dev/null @@ -1,71 +0,0 @@ -# Visualizing iFDO information with icons -Some of the iFDO fields require using well-defined values for those fields as described in the tables on the specific iFDO sections. For these well-defined values, icons were created to enable visualizing this capture information in web interfaces or data processing reports. These icons are available in the ressources folder and an overview is given here. You are free to use these icons. They are released publicly under CC-0. - -## iFDO core icons -| Field | Value | Icon | Description | -| ----- | ----- | ---- | ----------- | -| image-license | CC-BY |  | You are free to share and adapt the images as long as you give appropriate credit, link to the license, indicate your changes. | -| | CC-0 |  | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission | - -## iFDO capture icons -| Field | Value | Icon | Description | -| ----- | ----- | ---- | ----------- | -| image-acquisition | slide |  | The image set contains microscopy images / slide scans | -| | video |  | The image set contains moving images | -| | photo |  | The image set contains still images | -| image-quality | raw |  | The images in the image set come straight from the sensor | -| | product |  | The images in the image set are ready for interpretation | -| | processed |  | The images in the image set have been QA/QCd | -| image-deployment | exploration |  | The camera followed an unplanned path execution | -| | sampling |  | The camera imaging samples taken by other method ex-situ | -| | stationary |  | The camera remaind in a fixed spatial position | -| | survey |  | The camera followed a planned path execution along a free path | -| | experiment |  | The camera observed a manipulation of the environment | -| | mapping |  | The camera followed a planned path execution along 2-3 spatial axes | -| image-navigation | beacon |  | Position data was created from underwater beacons (USBL, ...) for an underwater position | -| | satellite |  | Position data was created from satellite information (GPS, Galileo, ...) for the sea surface | -| | transponder |  | Position data was created from underwater beacons (USBL, LBL, ...) for an underwater position | -| | reconstructed |  | Position data was estimated from other measures like cable length and course over ground | -| image-scale-reference | calibrated camera |  | Meter-scale in the images was determined by image data and additional external data like object distance | -| | laser marker |  | Meter-scale in the images was determined by laser markers visible in the images | -| | optical flow |  | Meter-scale in the images was determined from the relative movement of the images and the camera navigation data | -| | 3D camera |  | Meter-scale in the images was determined by 3D imaging / reconstruction | -| image-illumination | artificial |  | The scene is only illuminated by artificial light | -| | sun |  | The scene is only illuminated by the sun | -| | mixed |  | The scene is illuminated by both sunlight and artificial light | -| image-resolution | dm |  | The average size of a pixel in the image set is on the order of 1 dm = 0.1 m | -| | hm |  | The average size of a pixel in the image set is on the order of 1 hm = 100 m | -| | m |  | The average size of a pixel in the image set is on the order of 1 m | -| | cm |  | The average size of a pixel in the image set is on the order of 1 cm | -| | dam |  | The average size of a pixel in the image set is on the order of 1 dam = 10 m | -| | μm |  | The average size of a pixel in the image set is on the order of 1 µm | -| | mm |  | The average size of a pixel in the image set is on the order of 1 mm | -| | km |  | The average size of a pixel in the image set is on the order of 1 km | -| image-marine-zone | watercolumn |  | The images were taken in the water column without the seafloor or the sea surface in sight | -| | atmosphere |  | The images were taken outside of the water | -| | seasurface |  | The images were taken right below the sea surface | -| | laboratory |  | The images were taken ex-situ | -| | seafloor |  | The images were taken in/on/right above the seafloor | -| image-spectral-resolution | grayscale |  | The images consist of one color channel | -| | multi-spectral |  | The images consist of 4-10 color channels | -| | rgb |  | The images consist of three color channels | -| | hyper-spectral |  | The images consist of more than 10 channels | -| image-capture-mode | timer-and-manual |  | Image-acquisition was triggered by both a timer and a human-controller | -| | manual |  | Image-acquisition was triggered by a human controller | -| | timer |  | Image-acquisition was triggered by a timer | - -## iFDO content icons -| Field | Value | Icon | Description | -| ----- | ----- | ---- | ----------- | -| image-annotation-geometry-types | polygon |  | A detailed outline was drawn around objects of interest | -| | whole-image |  | The entire image was annotated without defining a region of interest | -| | bounding-box |  | A bounding box was drawn around objects of interest | -| | single-pixel |  | Single points in the images were marked | -| image-annotation-creator-types | non-expert |  | Annotations were created by trained, yet non-expert persons | -| | AI |  | Annotations were created by an artifical intelligence method | -| | expert |  | Annotations were created by trained experts | -| | crowd-sourced |  | Annotations were created by the general public | -| image-annotation-label-types | geology |  | Geological structures were annotated | -| | biology |  | Fauna and traces of life were annotated | -| | operation |  | Gear oeprations were annotated | -| | garbage |  | Garbage was annotated | diff --git a/docs/ifdos/iFDO-overview.md b/docs/ifdos/iFDO-overview.md deleted file mode 100644 index 84720baeea76520cebed41e9d5962c2bf2409327..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO-overview.md +++ /dev/null @@ -1,34 +0,0 @@ -# Introduction -Achieving FAIRness and Openness of (marine) image data requires structured and standardised metadata on the image data itself and the visual and semantic image data content. This metadata shall be provided in the form of FAIR digital objects (FDOs). These documentation pages describes how FDOs for images (aka iFDOs) shall be structured. If you want, an iFDO is a human and machine-readable file format for an entire image set, except that it does not contain the actual image data, only references to it through persistent identifiers! -iFDOs consist of various metadata fields. Some are required, some are recommended, some are optional. You will only achieve FAIRness of your image data with the required iFDO core fields populated. You will only gain visibility and credit for your image data with the recommended capture fields populated. And you will only have awesome image data in case you also populate the content fields. As a bonus you can add your own domain-specific optional fields. - -# iFDO - image FAIR Digital Object -Marine image data collections need a set of standardized metadata to achieve FAIRness of the data for open publication. An entire image set (e.g. deployment, station, dive, mission) requires information on the ownership and allowed usage of the collection. Numerical metadata is required for each image on its acquisition position. It is recommended to provide further optional metadata based on the imaging use case. The iFDO standard defines a format to structure such metadata. It was developed by the MareHub working group and the Marine Imaging Community. The future if iFDOs is described in the [roadmap](../roadmap.md). The development of the format is decumented on the [versions](../versions.md) page. - -### Quick facts: -- iFDOs are made for photos ([still images](http://purl.org/dc/dcmitype/StillImage)) and videos ([moving images](http://purl.org/dc/dcmitype/MovingImage)) -- iFDOs consist of an `image-set-header` an `image-set-items` [part](#ifdo-parts) -- iFDOs group metadata fields in three [sections](#ifdo-sections): iFDO core, iFDO capture and iFDO content -- iFDO [core](iFDO-core.md) fields are mandatory -- iFDO [capture](iFDO-capture.md) and [content](iFDO-content.md) fields are optional but recommended -- iFDO fields can be [mapped](iFDO_vocabulary-term-mapping.md) to many other metadata standards -- iFDOs make image data [FAIR](../FAIR-marine-images.md) without requiring them to be open, access-restriction remains possible -- iFDO field names use [kebab-case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case) -- The iFDO documentation is written with Python implementation in mind -- A peer-reviewed manuscript on iFDOs is available at Nature Scientific Data: https://doi.org/10.1038/s41597-022-01491-3 - -### iFDO files -All image metadata shall be stored in one image FAIR digital object (iFDO) file. This file shall contain all iFDO metadata fields. The file should be human and machine-readable, hence *.yaml format is recommended. The file name should be unique, we recommend: `<image-project>_<image-event>_<image-sensor>`_iFDO.yaml. iFDO files have to be well-formatted according to the documentation on these pages. They are light-weight and can evolve along their lifecycle. - - -### iFDO parts -An iFDO file consists of two parts: the `image-set-header` part and the `image-set-items` part. The header part contains default values for all items. The items part contains all values that deviate from the default values for this specific image item. The `image-set-header` part is a dictionary within which each metadata field is referenced by a key term such as `image-set-uuid`. The `image-set-items` part is also a dictionary, where the keys are the filenames of the images (i.e. photos or videos). All metadata of an image-item is provided in a list. For still images (aka photos) this list has only one object as an entry. For videos, the first entry of the list contains an object of those metadata fields that are defaults for the entire video. All subsequent list entries correspond to specifications of the metadata for one given timepoint of the video. - -### iFDO sections -The iFDO standard defines three different section that cover different aspects of FAIRness and target increasing usability of the image metadata. The [iFDO core](iFDO-core.md) section contains the required metadata that makes image data sets FAIR. The [iFDO capture](iFDO-capture.md) section contains metadata fields that describe how the image data was created. The [iFDO content](iFDO-content.md) section describes what is going on in the image data in terms of information or annotations. - - -### Mapping to other image metadata standards -The iFDOs standard aspires to be the most complete standard that allows to bridge between existing standards (like DublinCore, Audubon, SmartarID, PDS4) while filling gaps among those. We maintain a [term mapping](iFDO_vocabulary-term-mapping.md) of vocabulary terms to other standards. - - diff --git a/docs/ifdos/iFDO_vocabulary-term-mapping.md b/docs/ifdos/iFDO_vocabulary-term-mapping.md deleted file mode 100644 index 9ba4108645d49b3495ce580ee767202b0be49cc7..0000000000000000000000000000000000000000 --- a/docs/ifdos/iFDO_vocabulary-term-mapping.md +++ /dev/null @@ -1,84 +0,0 @@ -# Mapping iFDO fields to other standards -Fields of the [iFDO](iFDO-overview.md) image metadata standard are inspired by other metadata standards. iFDOs are designed to facilitate mapping between all relevant image metadata standards. - -## iFDO core fields (required) -| [iFDOs](iFDO-overview.md) | [DarwinCore](https://dwc.tdwg.org/terms) | [Pangaea](https://wiki.pangaea.de/wiki/Data_submission) | [schema.org](https://schema.org/docs/schemas.html) | [OBIS](https://obis.org/manual/darwincore/) | [MEDIN/BODC](https://www.medin.org.uk/sites/medin/files/documents/MEDIN_Schema_Documentation3_1_brief.pdf) | [Audubon](https://ac.tdwg.org/termlist) | [SMarTaR-ID](https://doi.org/10.1371/journal.pone.0218904) | -| - | - | - | - | - | - | - | - | -| image-set-name | datasetName | Dataset:Title | name | datasetName | Resource title | | | -| image-set-uuid | datasetID | | identifier | datasetID | Unique resource identifier | | | -| image-set-handle | | DOI (after publication) | | | | ac:accessURI | | -| image-datetime | eventDate | DATE/TIME (1599) | dateCreated | eventDate | Temporal reference | ac:startTime | dateIdentified | -| image-latitude | decimalLatitude | LATITUDE (1600) | | decimalLatitude | | dwc:decimalLatitude | decimalLatitude | -| image-longitude | decimalLongitude | LONGITUDE (1601) | | decimalLongitude | | dwc:decimalLongitude | decimalLongitude | -| image-depth | verbatimDepth | DEPTH, water [m] (1619) | | minimumDepthInMeters / maximumDepthInMeters | Vertical extent information | dwc:minimumDepthInMeters / dwc:maximumDepthInMeters | minimumDepthInMeters / maximumDepthInMeters | -| image-altitude | verbatimElevation | ALTITUDE [m] (4607) | | | | | | -| image-coordinate-reference-system | verbatimSRS | | | verbatimSRS | Spatial reference system | | | -| image-coordinate-uncertainty-meters | coordinatePrecision | Coordinate uncertainty (170981) | | coordinateUncertaintyInMeters | | dwc:pointRadiusSpatialFit | | -| image-project | | Dataset:Project | isPartOf | | | | | -| image-context | | | | | | | | -| image-event | | Event | | | | | | -| image-platform | | Event:Platform | | | | | | -| image-sensor | | Event:Sensor | | | | ac:captureDevice? | | -| image-uuid | eventID | | identifier | eventID | | | | -| image-hash-sha256 | | | | | | ac:hashValue | | -| image-filename | | File name (25541) | name | | | | | -| image-pi | | Dataset:PI | | | Originator | | | -| image-creators | rightsHolder | Dataset:Authors | creator | rightsHolder | Responsible party | dc::creator | | -| image-license | license | Dataset:License | license | license | Limitations on public access/ Conditions applying for access and use | | | -| image-copyright | | | | | | | | -| image-abstract | | Dataset:Abstract | | | Resource abstract | | | - -## iFDO capture fields (recommended) -| [iFDOs](iFDO-overview.md) | [DarwinCore](https://dwc.tdwg.org/terms) | [Pangaea](https://wiki.pangaea.de/wiki/Data_submission) | [schema.org](https://schema.org/docs/schemas.html) | [OBIS](https://obis.org/manual/darwincore/) | [MEDIN/BODC](https://www.medin.org.uk/sites/medin/files/documents/MEDIN_Schema_Documentation3_1_brief.pdf) | [Audubon](https://ac.tdwg.org/termlist) | [SMarTaR-ID](https://doi.org/10.1371/journal.pone.0218904) | -| - | - | - | - | - | - | - | - | -| image-acquisition | type | | ImageObject / VideoObject | type | Resource type / Data format | dc:format? | | -| image-quality | | | | | | | | -| image-deployment | | | | | | | | -| image-navigation | | | | | | | | -| image-scale-reference | | | | | | | | -| image-illumination | | | | | | | | -| image-resolution | | | | | | | | -| image-marine-zone | | | | | | | | -| image-spectral-resolution | | | | | | | | -| image-capture-mode | | | | | | | | -| image-area-square-meter | | | | | | | | -| image-pixel-per-millimeter | | Image resolution (172673) | | | Spatial resolution | | | -| image-meters-above-ground | | HEIGHT above ground [m] (56349) | | | Distance | | | -| image-acquisition-settings | | | | | Lineage(?) | | | -| image-camera-yaw-degrees | | | | | | | | -| image-camera-pitch-degrees | | | | | | | | -| image-camera-roll-degrees | | | | | | | | -| image-camera-pose | | | | | | | | -| image-camera-housing-viewport | | | | | | | | -| image-camera-flatport-parameters | | | | | | | | -| image-camera-domeport-parameters | | | | | | | | -| image-camera-calibration-model | | | | | | | | -| image-camera-photometric-calibration | | | | | | | | -| image-objective | | | | | | | | -| image-target-environment | | | | | | dwc:locationRemarks? | | -| image-target-timescale | | | | | | | | -| image-spatial-constraints | footprintWKT? | | | | | dwc:footprintWKT? | locality? | -| image-temporal-constraints | | | | | | dcterms:temporal? | | -| image-reference-calibration | | | | | | | | -| image-time-synchronization | | | | | | | | -| image-item-identification-scheme | | | | | | | | -| image-curation-protocol | | | | | | | | - -## iFDO content fields (optional) -| [iFDOs](iFDO-overview.md) | [DarwinCore](https://dwc.tdwg.org/terms) | [Pangaea](https://wiki.pangaea.de/wiki/Data_submission) | [schema.org](https://schema.org/docs/schemas.html) | [OBIS](https://obis.org/manual/darwincore/) | [MEDIN/BODC](https://www.medin.org.uk/sites/medin/files/documents/MEDIN_Schema_Documentation3_1_brief.pdf) | [Audubon](https://ac.tdwg.org/termlist) | [SMarTaR-ID](https://doi.org/10.1371/journal.pone.0218904) | -| - | - | - | - | - | - | - | - | -| image-entropy | | | | | | | | -| image-particle-count | | | | | | | | -| image-average-color | | | | | | | | -| image-mpeg7-... | | | | | | | | -| image-annotations | | | | | | ac:subjectOrientation? | | -| image-annotation-labels | taxonID? | | | | | dwc:scientificName? | scientificName / scientificNameID | -| image-annotation-creators | identifiedBy? | | | | | dwc:identifiedBy? | identifiedBy | - - -## Disclaimer -Vocabularies, repositories or other sources that do not enforce structured meta data or data (like Zenodo or DRYAD) are not considered here as they do not lead to FAIRness of data. Similarly, all projects, workflows, etc. that rely on these sources are omitted as well. - -Other sources not (yet?) included here: -- http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.733.1984&rep=rep1&type=pdf -- https://www.nature.com/articles/sdata2018181 diff --git a/docs/ifdos/ifdo-visualization.md b/docs/ifdos/ifdo-visualization.md deleted file mode 100644 index 16404992742699031a99742a4e1f69b34a556939..0000000000000000000000000000000000000000 --- a/docs/ifdos/ifdo-visualization.md +++ /dev/null @@ -1,3 +0,0 @@ -# IFDO Visualization - -<iframe src="https://datahub.pages.hzdr.de/marehub/ag-videosimages/ifdo-applications/visualization/" style="width: 150%; height: 80vh; border: none;"> diff --git a/docs/ifdos/svgs/image-annotation-creator_AI.svg b/docs/ifdos/svgs/image-annotation-creator_AI.svg deleted file mode 100644 index fb4945568f8929a4684d326f31276d3af89911e4..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-creator_AI.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-creator_AI" alt="image-set-annotation-creator is AI" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-creator is AI</title><style type="text/css">.image-set-annotation-creator-AI-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-creator-AI-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.8833,1.8833;}.image-set-annotation-creator-AI-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0267,2.0267;}.image-set-annotation-creator-AI-st3{fill:#FFFFFF;}.image-set-annotation-creator-AI-st4{fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}.image-set-annotation-creator-AI-st5{fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:10;}.image-set-annotation-creator-AI-st6{stroke:#FFFFFF;stroke-width:0.25;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-creator-AI-st0" points="38.3,31.8 38.3,32.8 37.3,32.8 "/><line class="image-set-annotation-creator-AI-st1" x1="35.4" y1="32.8" x2="6.2" y2="32.8"/><polyline class="image-set-annotation-creator-AI-st0" points="5.3,32.8 4.3,32.8 4.3,31.8 "/><line class="image-set-annotation-creator-AI-st2" x1="4.3" y1="29.7" x2="4.3" y2="6.4"/><polyline class="image-set-annotation-creator-AI-st0" points="4.3,5.4 4.3,4.4 5.3,4.4 "/><line class="image-set-annotation-creator-AI-st1" x1="7.2" y1="4.4" x2="36.4" y2="4.4"/><polyline class="image-set-annotation-creator-AI-st0" points="37.3,4.4 38.3,4.4 38.3,5.4 "/><line class="image-set-annotation-creator-AI-st2" x1="38.3" y1="7.4" x2="38.3" y2="30.7"/></g></g><g><path d="M24.4,53.3c-0.4,0-0.7-0.2-0.9-0.6l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.1,0.2,0.1,0.5,0,0.8s-0.3,0.4-0.5,0.6l-2.8,1.2C24.7,53.3,24.6,53.3,24.4,53.3z"/><path class="image-set-annotation-creator-AI-st3" d="M15.8,29.6l12.6,13.3l-5.1-0.2l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L15.8,29.6 M15.8,27.6c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2L15.5,48c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L17.3,28.2C16.9,27.8,16.4,27.6,15.8,27.6L15.8,27.6z"/></g><g><path class="image-set-annotation-creator-AI-st4" d="M21.2,15.4c0,0.3-0.1,0.7-0.1,1c-0.1,0.9,0.2,1.7,0.6,2.6c0.4,0.8,0.6,1.6,0.6,2.4c0,0.9-0.3,1.8-0.7,2.6c-0.7,1.4-0.7,2.9-0.1,4.3c0.2,0.5,0.4,0.9,0.6,1.3c0.2,0.2,0.2,0.5,0.2,0.9"/><path class="image-set-annotation-creator-AI-st4" d="M17.4,14.3c0.1,0.5-0.2,0.9-0.2,1.5c-0.2,1-0.1,2,0.4,3c0.3,0.6,0.6,1.3,0.7,2.1c0.2,0.9-0.1,1.7-0.4,2.6c-0.2,0.5-0.5,1.2-0.7,1.8c-0.2,0.8-0.2,1.6,0.1,2.3c0.1,0.2,0.1,0.5,0.1,0.7"/><path class="image-set-annotation-creator-AI-st4" d="M25.4,14.3c0.1,0.4-0.1,0.8-0.2,1.2c-0.3,1.2-0.2,2.3,0.4,3.3c0.2,0.5,0.5,1.1,0.6,1.6c0.2,1.1,0.1,2.1-0.5,3.1c-0.4,0.7-0.6,1.5-0.7,2.3c-0.1,0.5,0.1,1,0.2,1.6c0.1,0.2,0.1,0.5,0.1,0.7"/><g><g><g><path d="M28,17.2c-0.7,0-1.3-0.2-1.8-0.7c-0.2-0.2-0.4-0.3-0.5-0.5c-0.1-0.1-0.2-0.1-0.3-0.1S25.1,16,25,16.1c-0.1,0.1-0.2,0.2-0.3,0.2c-0.5,0.4-1,0.6-1.6,0.6c-0.6,0-1.2-0.2-1.7-0.8c-0.2-0.2-0.4-0.4-0.5-0.4c-0.1,0-0.2,0.1-0.5,0.2c-0.5,0.3-0.9,0.5-1.4,0.5c-0.5,0-0.9-0.2-1.2-0.4c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.6,0.1-0.9,0.4c-0.5,0.4-1,0.5-1.7,0.5c-0.2,0-0.5,0-0.9-0.1c-0.5-0.1-0.8-0.4-0.9-0.9c-0.1-0.2-0.1-0.4-0.2-0.6l-0.1-0.3v-0.1c0.2-2.2,1.1-3.8,2.4-5.1c1.4-1.3,3.1-2.2,5.1-2.5c0.6-0.1,1.2-0.2,1.7-0.2c1.9,0,3.7,0.5,5.4,1.6c1.9,1.2,3,2.8,3.3,4.8c0.2,0.7,0.2,1.4,0.1,2.2c-0.2,0.7-0.6,1.2-1.2,1.3C28.6,17.1,28.3,17.2,28,17.2z"/><path class="image-set-annotation-creator-AI-st3" d="M21.3,7.5c1.8,0,3.6,0.5,5.1,1.6c1.6,1.1,2.8,2.6,3.2,4.6c0.2,0.7,0.2,1.3,0.1,2c-0.2,0.5-0.5,0.9-1,1c-0.3,0.1-0.5,0.1-0.8,0.1c-0.5,0-1.1-0.2-1.6-0.6c-0.2-0.2-0.4-0.3-0.6-0.5c-0.2-0.2-0.4-0.2-0.5-0.2c-0.2,0-0.4,0.1-0.5,0.2c-0.1,0.1-0.2,0.2-0.3,0.2c-0.4,0.3-0.9,0.5-1.3,0.5c-0.5,0-1.1-0.2-1.5-0.6c-0.3-0.3-0.5-0.5-0.8-0.5c-0.2,0-0.5,0.1-0.7,0.3c-0.4,0.3-0.8,0.5-1.2,0.5c-0.4,0-0.7-0.1-1.1-0.3s-0.7-0.3-1.1-0.3S16,15.7,15.6,16c-0.5,0.3-0.9,0.5-1.5,0.5c-0.3,0-0.5,0-0.9-0.1c-0.3-0.1-0.5-0.2-0.6-0.5c-0.1-0.3-0.1-0.5-0.2-0.9c0.2-1.9,0.9-3.6,2.3-4.9c1.4-1.3,3-2.1,4.9-2.3C20.2,7.5,20.8,7.5,21.3,7.5 M21.3,6.8L21.3,6.8c-0.6,0-1.2,0.1-1.8,0.2c-2.1,0.3-3.9,1.2-5.3,2.6s-2.3,3.1-2.5,5.4V15v0.2l0.1,0.2c0,0.2,0.1,0.4,0.2,0.6c0.2,0.6,0.6,1,1.2,1.1c0.4,0.1,0.7,0.1,1,0.1c0.8,0,1.4-0.2,1.9-0.6c0.3-0.2,0.5-0.3,0.7-0.3c0.2,0,0.4,0.1,0.7,0.2c0.5,0.3,1,0.5,1.5,0.5c0.6,0,1.2-0.2,1.6-0.6c0.2-0.1,0.2-0.2,0.2-0.2c0.1,0,0.2,0.1,0.2,0.2c0.5,0.5,1.2,0.9,2,0.9c0.7,0,1.3-0.2,1.9-0.7c0.1-0.1,0.2-0.2,0.2-0.2c0.1-0.1,0.2-0.1,0.2-0.1s0.1,0,0.1,0.1c0.2,0.1,0.3,0.2,0.5,0.4c0.6,0.5,1.3,0.8,2.1,0.8c0.3,0,0.6-0.1,1-0.2c0.8-0.2,1.3-0.8,1.6-1.6c0.2-0.9,0.1-1.7-0.1-2.4c-0.4-2.1-1.6-3.8-3.6-5.1C25.2,7.3,23.3,6.8,21.3,6.8L21.3,6.8z"/></g></g></g></g><g><g><line x1="57.7" y1="55.2" x2="76.1" y2="55.2"/><line class="image-set-annotation-creator-AI-st5" x1="57.7" y1="55.2" x2="76.1" y2="55.2"/><path d="M78.8,55.2c0,1.5-1.2,2.8-2.8,2.8s-2.8-1.2-2.8-2.8s1.2-2.8,2.8-2.8S78.8,53.6,78.8,55.2"/><polyline class="image-set-annotation-creator-AI-st5" points="57.7,50.1 67.6,50.1 71.6,43.3 76.1,43.3 "/><path d="M80.7,43.3c0,1.5-1.2,2.8-2.8,2.8s-2.8-1.2-2.8-2.8s1.2-2.8,2.8-2.8S80.7,41.8,80.7,43.3"/><polyline class="image-set-annotation-creator-AI-st5" points="57.7,43.2 60.6,43.2 62.9,36.3 65.6,36.3 "/><path d="M70.3,36.3c0,1.5-1.2,2.8-2.8,2.8c-1.5,0-2.8-1.2-2.8-2.8c0-1.5,1.2-2.8,2.8-2.8C69,33.6,70.3,34.8,70.3,36.3"/><polyline class="image-set-annotation-creator-AI-st5" points="57.7,60 67.6,60 71.6,66.8 75.3,66.8 "/><path d="M80,66.8c0-1.5-1.2-2.8-2.8-2.8c-1.5,0-2.8,1.2-2.8,2.8c0,1.5,1.2,2.8,2.8,2.8C78.7,69.6,80,68.4,80,66.8"/><polyline class="image-set-annotation-creator-AI-st5" points="57.7,66.9 60.6,66.9 62.9,73.8 65.6,73.8 "/><path d="M70.3,73.8c0-1.5-1.2-2.8-2.8-2.8c-1.5,0-2.8,1.2-2.8,2.8c0,1.5,1.2,2.8,2.8,2.8C69,76.5,70.3,75.3,70.3,73.8"/></g><path class="image-set-annotation-creator-AI-st6" d="M36.4,41.5c0-4.8,3.6-7.2,7.8-6.6c1.2-2.4,2.9-3.9,5.7-4c3.6-0.1,6.3,2.6,6.3,6.2c0,10.4,0,20.7,0,31.1c0,2.1,0,4.2,0,6.2c0,2.9-1.8,5.3-4.6,6c-2.6,0.7-5.6-0.5-6.9-3c-0.4-0.8-0.8-1-1.7-0.9c-3.9,0.4-6.8-2.5-6.7-6.8c-0.5-0.2-1-0.4-1.6-0.6c-2.9-1.4-4.2-4.7-3.2-7.7c0.1-0.4,0.2-1.1-0.1-1.4c-2.6-3.4-2.4-6.3,0.9-9.4c-0.8-1.8-1.2-3.7-0.3-5.7C32.8,43.1,34.4,42,36.4,41.5 M38.5,41.3c0.1,0.1,0.2,0.1,0.3,0.2c2.6,0.7,4.4,2.2,4.8,5c0.2,1.4,1.2,2.2,2.6,2.5c0.4,0.1,0.7,0.7,1.1,1c-0.5,0.3-1,0.8-1.5,0.7c-2.2-0.2-3.7-1.7-4.3-4.3c-0.5-2.4-2.9-3.7-5.3-3c-2.2,0.6-3.5,3.1-2.8,5.3c0.3,0.8,0.7,1.3,1.6,1.1c0.6-0.1,1.3,0,2,0.1c2.7,0.5,5,3.3,4.8,5.8c0,0.4-0.5,1-0.7,1c-0.4,0-0.8-0.4-1.2-0.8c-0.2-0.1-0.1-0.5-0.1-0.8c-0.4-2.2-2.1-3.6-4.3-3.5c-2.1,0.1-3.9,1.8-4.1,3.8c-0.2,2.1,1.3,4,3.4,4.4c0.7,0.2,1.9-0.1,1.7,1.1c-0.2,1.3-1.3,0.8-2.1,0.7c-1-0.2-1.3,0.3-1.5,1.1c-0.4,2.5,1.2,4.6,3.8,5c2.2,0.3,4.3-1.5,4.6-3.8c0.1-0.6,0.1-1.2,0.3-1.8c0.7-2.2,2.8-3.5,5.2-3.3c2.1,0.2,4.1,2,4.2,4.1c0,0.4-0.5,0.9-0.8,1.4c-0.4-0.3-0.7-0.7-1.1-1c-0.1-0.1,0-0.2,0-0.3c-0.3-1.5-1.6-2.5-3-2.5c-1.4,0.1-2.6,1.2-2.8,2.7c-0.1,0.4-0.1,0.8-0.1,1.2c-0.4,2.2-1.5,3.7-3.6,4.6c-1.6,0.7-1.8,1.2-1.2,2.8c0.6,1.5,1.7,2.5,3.3,2.8c1.4,0.3,1.9-0.1,2.2-1.5c0.5-2.6,3-4.7,5.5-4.8c0.7,0,1.4,0.1,1.3,0.9c0,0.4-0.6,0.7-1,1c-0.2,0.1-0.5,0.1-0.8,0.1c-1.9,0.4-3.3,2.1-3.2,3.9c0,2.4,1.9,4.4,4.2,4.4c2.3,0,4.2-1.9,4.2-4.4c0-6.8,0-13.6,0-20.3c0-5.7,0-11.3,0-17c0-2.6-2.2-4.5-4.6-4.2c-2.2,0.3-3.7,1.9-3.8,4c-0.1,2.2,1.4,4,3.8,4.4c0.7,0.1,1.5,0,1.3,1c-0.1,1-1,0.9-1.7,0.8c-2.5-0.3-4.7-2.3-5.2-4.8c-0.1-0.5-0.2-0.9-0.3-1.4C40.6,36.3,38.3,38.2,38.5,41.3"/></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-creator_crowd-sourced.svg b/docs/ifdos/svgs/image-annotation-creator_crowd-sourced.svg deleted file mode 100644 index 9200c0d809c2babbc75c049b3257624f07b42ef6..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-creator_crowd-sourced.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-creator_crowd-sourced" alt="image-set-annotation-creator is crowd-sourced" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-creator is crowd-sourced</title><style type="text/css">.image-set-annotation-creator-crowd-sourced-st0{fill:#FFFFFF;}.image-set-annotation-creator-crowd-sourced-st1{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-creator-crowd-sourced-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.8833,1.8833;}.image-set-annotation-creator-crowd-sourced-st3{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0267,2.0267;}.image-set-annotation-creator-crowd-sourced-st4{fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><g><path d="M57,58.7c-2.8,0-5.2-2.2-6.1-5.7l-1.2-5.9c-3.2-0.7-3.2-3.7-3.2-5.9c0.5-5.5,1.7-8.7,4.5-11.1c-1.1-1.3-1.6-3-1.6-4.7c0-4.2,3.4-7.6,7.6-7.6s7.6,3.4,7.6,7.6c0,1.7-0.6,3.3-1.6,4.7c2.8,2.4,4.1,5.5,4.5,10.8c0,2.6,0,5.5-3.1,6.2l-1.2,5.8C62.2,56.5,59.8,58.7,57,58.7z M54.2,32.4c-0.1,0.1-0.2,0.2-0.3,0.3c-2,1.6-3.2,3.5-3.6,8.8c0,0.9,0,1.9,0.2,2.1c0,0,0.2,0.1,0.9,0.1c0.9,0,1.6,0.6,1.8,1.5l1.4,7.2c0.4,1.6,1.4,2.8,2.5,2.8s2.1-1.2,2.5-2.9l1.4-7c0.2-0.9,0.9-1.5,1.8-1.5c0.7,0,0.8-0.1,0.9-0.1c0.1-0.2,0.1-1.3,0.1-2.4c-0.4-5-1.6-6.9-3.6-8.5c-0.1-0.1-0.2-0.2-0.3-0.3c-0.7,0.2-1.9,0.5-2.8,0.5C56,32.8,54.9,32.6,54.2,32.4z M57,21.6c-2.1,0-3.9,1.7-3.9,3.9c0,2.1,1.7,3.9,3.9,3.9s3.9-1.7,3.9-3.9C60.9,23.3,59.1,21.6,57,21.6z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M57,18.9c3.6,0,6.6,2.9,6.6,6.6c0,1.6-0.6,3.1-1.7,4.3l-0.4,0.5l0.5,0.4c2.8,2.3,4,5.2,4.5,10.4c0,2.9-0.2,4.7-2.6,5.2l-0.4,0.1l-1.3,6.5c-0.8,3-2.8,5-5.1,5c-2.4,0-4.4-1.9-5.1-4.9l-1.3-6.5l-0.4-0.1c-2.4-0.4-2.6-2.3-2.6-5c0.4-5.3,1.7-8.3,4.5-10.6l0.5-0.4l-0.4-0.5c-1.1-1.2-1.7-2.8-1.7-4.3C50.4,21.9,53.4,18.9,57,18.9 M57,30.3c2.7,0,4.9-2.2,4.9-4.9c0-2.7-2.2-4.9-4.9-4.9c-2.7,0-4.9,2.2-4.9,4.9C52.1,28.2,54.3,30.3,57,30.3 M57,31.8c-1.4,0-3.2-0.6-3.2-0.6l-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-2.2,1.7-3.5,3.8-4,9.5c0,2.7,0,3.3,2,3.3c0.4,0,0.8,0.3,0.8,0.7l1.4,7.2c0.5,2.2,1.9,3.6,3.4,3.6c1.6,0,2.9-1.4,3.5-3.7l1.4-7.1c0.1-0.4,0.4-0.7,0.8-0.7c2,0,2-0.6,2-3.5c-0.5-5.5-1.9-7.6-4-9.3c-0.1,0-0.1-0.1-0.1-0.2l-0.4-0.5C60.2,31.2,58.2,31.8,57,31.8 M57,16.9c-4.7,0-8.6,3.8-8.6,8.6c0,1.6,0.5,3.2,1.3,4.5c-2.5,2.5-3.7,5.8-4.2,11.1l0,0.1l0,0.1c0,2.1,0,5.6,3.3,6.7l1.1,5.3l0,0l0,0c1,3.9,3.7,6.4,7,6.4c3.3,0,6.1-2.6,7.1-6.5l0,0l0,0l1-5.2c3.3-1.1,3.3-4.6,3.3-6.9l0-0.1l0-0.1c-0.4-5.1-1.7-8.4-4.2-10.9c0.9-1.4,1.3-2.9,1.3-4.5C65.6,20.8,61.7,16.9,57,16.9L57,16.9z M57,28.3c-1.6,0-2.9-1.3-2.9-2.9c0-1.6,1.3-2.9,2.9-2.9c1.6,0,2.9,1.3,2.9,2.9C59.9,27.1,58.6,28.3,57,28.3L57,28.3z M57,33.8c0.8,0,1.8-0.2,2.6-0.4c1.4,1.1,2.7,2.6,3.2,7.8c0,0.5,0,1,0,1.4c-1.3,0-2.5,1-2.8,2.3l-1.4,7c-0.3,1.3-1,2.1-1.5,2.1c-0.5,0-1.2-0.7-1.5-2l-1.4-7.1c-0.3-1.3-1.4-2.3-2.8-2.3c0-0.3,0-0.8,0-1.2c0.5-5.3,1.7-6.7,3.2-7.9C55.2,33.6,56.1,33.8,57,33.8L57,33.8z"/></g><path class="image-set-annotation-creator-crowd-sourced-st0" d="M60.2,31.2l0.4,0.5c0,0.1,0.1,0.1,0.1,0.2c2.1,1.7,3.5,3.8,4,9.3c0,2.9,0,3.5-2,3.5c-0.4,0-0.8,0.3-0.8,0.7l-1.4,7.1c-0.6,2.2-1.9,3.7-3.5,3.7c-1.6,0-2.9-1.4-3.4-3.6l-1.4-7.2c-0.1-0.4-0.4-0.7-0.8-0.7c-2,0-2-0.6-2-3.3c0.5-5.6,1.8-7.7,4-9.5c0.1,0,0.1-0.1,0.1-0.2l0.4-0.5c0,0,1.8,0.6,3.2,0.6C58.2,31.8,60.2,31.2,60.2,31.2z"/><circle class="image-set-annotation-creator-crowd-sourced-st0" cx="57" cy="25.5" r="4.9"/></g><g><g><path d="M71.3,72.4c-2.8,0-5.2-2.2-6.1-5.7l-1.2-5.9c-3.2-0.7-3.2-3.7-3.2-5.9c0.5-5.5,1.7-8.7,4.5-11.1c-1.1-1.3-1.6-3-1.6-4.7c0-4.2,3.4-7.6,7.6-7.6c4.2,0,7.6,3.4,7.6,7.6c0,1.7-0.6,3.3-1.6,4.7c2.8,2.4,4,5.5,4.5,10.8c0,2.6,0,5.5-3.1,6.2l-1.2,5.8C76.5,70.1,74.2,72.4,71.3,72.4z M68.5,46c-0.1,0.1-0.2,0.2-0.3,0.3c-2,1.6-3.2,3.5-3.6,8.8c0,0.9,0,1.9,0.2,2.1c0,0,0.2,0.1,0.9,0.1c0.9,0,1.6,0.6,1.8,1.5l1.4,7.2c0.4,1.6,1.4,2.8,2.5,2.8s2.1-1.2,2.5-2.9l1.4-7c0.2-0.9,0.9-1.5,1.8-1.5c0.7,0,0.8-0.1,0.9-0.1c0.1-0.2,0.1-1.3,0.1-2.4c-0.4-5-1.6-7-3.6-8.5c-0.1-0.1-0.2-0.2-0.3-0.3c-0.7,0.2-1.9,0.5-2.8,0.5C70.3,46.5,69.2,46.2,68.5,46z M71.3,35.2c-2.1,0-3.9,1.7-3.9,3.9c0,2.1,1.7,3.9,3.9,3.9c2.1,0,3.9-1.7,3.9-3.9C75.2,37,73.5,35.2,71.3,35.2z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M71.3,32.6c3.6,0,6.6,2.9,6.6,6.6c0,1.6-0.6,3.1-1.7,4.3l-0.4,0.5l0.5,0.4c2.8,2.3,4,5.2,4.5,10.4c0,2.9-0.2,4.7-2.6,5.2l-0.4,0.1l-1.3,6.5c-0.8,3-2.8,5-5.1,5c-2.4,0-4.4-1.9-5.1-4.9l-1.3-6.5l-0.4-0.1c-2.4-0.4-2.6-2.3-2.6-5c0.4-5.3,1.7-8.3,4.5-10.6l0.5-0.4l-0.4-0.5c-1.1-1.2-1.7-2.8-1.7-4.3C64.8,35.5,67.7,32.6,71.3,32.6 M71.3,44c2.7,0,4.9-2.2,4.9-4.9c0-2.7-2.2-4.9-4.9-4.9s-4.9,2.2-4.9,4.9C66.5,41.8,68.6,44,71.3,44 M71.3,45.5c-1.4,0-3.2-0.6-3.2-0.6l-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-2.2,1.7-3.5,3.8-4,9.5c0,2.7,0,3.3,2,3.3c0.4,0,0.8,0.3,0.8,0.7l1.4,7.2c0.5,2.2,1.9,3.6,3.4,3.6c1.6,0,2.9-1.4,3.5-3.7l1.4-7.1c0.1-0.4,0.4-0.7,0.8-0.7c2,0,2-0.6,2-3.5c-0.5-5.5-1.9-7.6-4-9.3c-0.1,0-0.1-0.1-0.1-0.2l-0.4-0.5C74.5,44.8,72.6,45.5,71.3,45.5 M71.3,30.6c-4.7,0-8.6,3.8-8.6,8.6c0,1.6,0.5,3.2,1.3,4.5c-2.5,2.5-3.7,5.8-4.2,11.1l0,0.1l0,0.1c0,2.1,0,5.6,3.3,6.7l1.1,5.3l0,0l0,0c1,3.9,3.7,6.4,7,6.4c3.3,0,6.1-2.6,7.1-6.5l0,0l0,0l1-5.2c3.3-1.1,3.3-4.6,3.3-6.9l0-0.1l0-0.1c-0.4-5.1-1.7-8.4-4.2-10.9c0.9-1.4,1.3-2.9,1.3-4.5C79.9,34.4,76,30.6,71.3,30.6L71.3,30.6z M71.3,42c-1.6,0-2.9-1.3-2.9-2.9c0-1.6,1.3-2.9,2.9-2.9c1.6,0,2.9,1.3,2.9,2.9C74.2,40.7,72.9,42,71.3,42L71.3,42z M71.3,47.5c0.8,0,1.8-0.2,2.6-0.4c1.4,1.1,2.7,2.6,3.2,7.8c0,0.5,0,1,0,1.4c-1.3,0-2.5,1-2.8,2.3l-1.4,7c-0.3,1.3-1,2.1-1.5,2.1c-0.5,0-1.2-0.7-1.5-2l-1.4-7.1c-0.3-1.3-1.4-2.3-2.8-2.3c0-0.3,0-0.8,0-1.2c0.5-5.3,1.7-6.7,3.2-7.9C69.5,47.3,70.4,47.5,71.3,47.5L71.3,47.5z"/></g><path class="image-set-annotation-creator-crowd-sourced-st0" d="M74.5,44.8l0.4,0.5c0,0.1,0.1,0.1,0.1,0.2c2.1,1.7,3.5,3.8,4,9.3c0,2.9,0,3.5-2,3.5c-0.4,0-0.8,0.3-0.8,0.7L74.8,66c-0.6,2.2-1.9,3.7-3.5,3.7c-1.6,0-2.9-1.4-3.4-3.6l-1.4-7.2c-0.1-0.4-0.4-0.7-0.8-0.7c-2,0-2-0.6-2-3.3c0.5-5.6,1.8-7.7,4-9.5c0.1,0,0.1-0.1,0.1-0.2l0.4-0.5c0,0,1.8,0.6,3.2,0.6C72.6,45.5,74.5,44.8,74.5,44.8z"/><circle class="image-set-annotation-creator-crowd-sourced-st0" cx="71.3" cy="39.1" r="4.9"/></g><g><g><path d="M42.7,72.4c-2.8,0-5.2-2.2-6.1-5.7l-1.2-5.9c-3.2-0.7-3.2-3.7-3.2-5.9c0.5-5.5,1.7-8.7,4.5-11.1c-1.1-1.3-1.6-3-1.6-4.7c0-4.2,3.4-7.6,7.6-7.6s7.6,3.4,7.6,7.6c0,1.7-0.6,3.3-1.6,4.7c2.8,2.4,4.1,5.5,4.5,10.8c0,2.6,0,5.5-3.1,6.2l-1.2,5.8C47.9,70.1,45.5,72.4,42.7,72.4z M39.8,46c-0.1,0.1-0.2,0.2-0.3,0.3c-2,1.6-3.2,3.5-3.6,8.8c0,0.9,0,1.9,0.2,2.1c0,0,0.2,0.1,0.9,0.1c0.9,0,1.6,0.6,1.8,1.5l1.4,7.2c0.4,1.6,1.4,2.8,2.5,2.8c1.1,0,2.1-1.2,2.5-2.9l1.4-7c0.2-0.9,0.9-1.5,1.8-1.5c0.7,0,0.8-0.1,0.9-0.1c0.1-0.2,0.1-1.3,0.1-2.4c-0.4-5-1.6-7-3.6-8.5c-0.1-0.1-0.2-0.2-0.3-0.3c-0.7,0.2-1.9,0.5-2.8,0.5C41.7,46.5,40.5,46.2,39.8,46z M42.7,35.2c-2.1,0-3.9,1.7-3.9,3.9c0,2.1,1.7,3.9,3.9,3.9c2.1,0,3.9-1.7,3.9-3.9C46.5,37,44.8,35.2,42.7,35.2z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M42.7,32.6c3.6,0,6.6,2.9,6.6,6.6c0,1.6-0.6,3.1-1.7,4.3l-0.4,0.5l0.5,0.4c2.8,2.3,4,5.2,4.5,10.4c0,2.9-0.2,4.7-2.6,5.2l-0.4,0.1l-1.3,6.5c-0.8,3-2.8,5-5.1,5c-2.4,0-4.4-1.9-5.1-4.9l-1.3-6.5l-0.4-0.1c-2.4-0.4-2.6-2.3-2.6-5c0.4-5.3,1.7-8.3,4.5-10.6l0.5-0.4l-0.4-0.5c-1.1-1.2-1.7-2.8-1.7-4.3C36.1,35.5,39.1,32.6,42.7,32.6 M42.7,44c2.7,0,4.9-2.2,4.9-4.9c0-2.7-2.2-4.9-4.9-4.9c-2.7,0-4.9,2.2-4.9,4.9C37.8,41.8,40,44,42.7,44 M42.7,45.5c-1.4,0-3.2-0.6-3.2-0.6l-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-2.2,1.7-3.5,3.8-4,9.5c0,2.7,0,3.3,2,3.3c0.4,0,0.8,0.3,0.8,0.7l1.4,7.2c0.5,2.2,1.9,3.6,3.4,3.6c1.6,0,2.9-1.4,3.5-3.7l1.4-7.1c0.1-0.4,0.4-0.7,0.8-0.7c2,0,2-0.6,2-3.5c-0.5-5.5-1.9-7.6-4-9.3c-0.1,0-0.1-0.1-0.1-0.2l-0.4-0.5C45.9,44.8,43.9,45.5,42.7,45.5 M42.7,30.6c-4.7,0-8.6,3.8-8.6,8.6c0,1.6,0.5,3.2,1.3,4.5c-2.5,2.5-3.7,5.8-4.2,11.1l0,0.1l0,0.1c0,2.1,0,5.6,3.3,6.7l1.1,5.3l0,0l0,0c1,3.9,3.7,6.4,7,6.4c3.3,0,6.1-2.6,7.1-6.5l0,0l0,0l1-5.2c3.3-1.1,3.3-4.6,3.3-6.9l0-0.1l0-0.1c-0.4-5.1-1.7-8.4-4.2-10.9c0.9-1.4,1.3-2.9,1.3-4.5C51.2,34.4,47.4,30.6,42.7,30.6L42.7,30.6z M42.7,42c-1.6,0-2.9-1.3-2.9-2.9c0-1.6,1.3-2.9,2.9-2.9c1.6,0,2.9,1.3,2.9,2.9C45.5,40.7,44.3,42,42.7,42L42.7,42z M42.7,47.5c0.8,0,1.8-0.2,2.6-0.4c1.4,1.1,2.7,2.6,3.2,7.8c0,0.5,0,1,0,1.4c-1.3,0-2.5,1-2.8,2.3l-1.4,7c-0.3,1.3-1,2.1-1.5,2.1c-0.5,0-1.2-0.7-1.5-2l-1.4-7.1c-0.3-1.3-1.4-2.3-2.8-2.3c0-0.3,0-0.8,0-1.2c0.5-5.3,1.7-6.7,3.2-7.9C40.8,47.3,41.8,47.5,42.7,47.5L42.7,47.5z"/></g><path class="image-set-annotation-creator-crowd-sourced-st0" d="M45.9,44.8l0.4,0.5c0,0.1,0.1,0.1,0.1,0.2c2.1,1.7,3.5,3.8,4,9.3c0,2.9,0,3.5-2,3.5c-0.4,0-0.8,0.3-0.8,0.7L46.2,66c-0.6,2.2-1.9,3.7-3.5,3.7c-1.6,0-2.9-1.4-3.4-3.6l-1.4-7.2c-0.1-0.4-0.4-0.7-0.8-0.7c-2,0-2-0.6-2-3.3c0.5-5.6,1.8-7.7,4-9.5c0.1,0,0.1-0.1,0.1-0.2l0.4-0.5c0,0,1.8,0.6,3.2,0.6C43.9,45.5,45.9,44.8,45.9,44.8z"/><circle class="image-set-annotation-creator-crowd-sourced-st0" cx="42.7" cy="39.1" r="4.9"/></g><g><g><path d="M57,81.5c-2.8,0-5.2-2.2-6.1-5.7L49.7,70c-3.2-0.7-3.2-3.7-3.2-5.9c0.5-5.5,1.7-8.7,4.5-11.1c-1.1-1.3-1.6-3-1.6-4.7c0-4.2,3.4-7.6,7.6-7.6s7.6,3.4,7.6,7.6c0,1.7-0.6,3.3-1.6,4.7c2.8,2.4,4.1,5.5,4.5,10.8c0,2.6,0,5.5-3.1,6.2l-1.2,5.8C62.2,79.3,59.8,81.5,57,81.5z M54.2,55.1c-0.1,0.1-0.2,0.2-0.3,0.3c-2,1.6-3.2,3.5-3.6,8.8c0,0.9,0,1.9,0.2,2.1c0,0,0.2,0.1,0.9,0.1c0.9,0,1.6,0.6,1.8,1.5l1.4,7.2c0.4,1.6,1.4,2.8,2.5,2.8s2.1-1.2,2.5-2.9l1.4-7c0.2-0.9,0.9-1.5,1.8-1.5c0.7,0,0.8-0.1,0.9-0.1c0.1-0.2,0.1-1.3,0.1-2.4c-0.4-5-1.6-6.9-3.6-8.5c-0.1-0.1-0.2-0.2-0.3-0.3c-0.7,0.2-1.9,0.5-2.8,0.5C56,55.6,54.9,55.3,54.2,55.1z M57,44.4c-2.1,0-3.9,1.7-3.9,3.9s1.7,3.9,3.9,3.9s3.9-1.7,3.9-3.9S59.1,44.4,57,44.4z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M57,41.7c3.6,0,6.6,2.9,6.6,6.6c0,1.6-0.6,3.1-1.7,4.3L61.5,53l0.5,0.4c2.8,2.3,4,5.2,4.5,10.4c0,2.9-0.2,4.7-2.6,5.2l-0.4,0.1l-1.3,6.5c-0.8,3-2.8,5-5.1,5c-2.4,0-4.4-1.9-5.1-4.9l-1.3-6.5L50.2,69c-2.4-0.4-2.6-2.3-2.6-5c0.4-5.3,1.7-8.3,4.5-10.6l0.5-0.4l-0.4-0.5c-1.1-1.2-1.7-2.8-1.7-4.3C50.4,44.6,53.4,41.7,57,41.7 M57,53.1c2.7,0,4.9-2.2,4.9-4.9c0-2.7-2.2-4.9-4.9-4.9c-2.7,0-4.9,2.2-4.9,4.9C52.1,50.9,54.3,53.1,57,53.1 M57,54.6c-1.4,0-3.2-0.6-3.2-0.6l-0.4,0.5c0,0.1-0.1,0.1-0.1,0.2c-2.2,1.7-3.5,3.8-4,9.5c0,2.7,0,3.3,2,3.3c0.4,0,0.8,0.3,0.8,0.7l1.4,7.2c0.5,2.2,1.9,3.6,3.4,3.6c1.6,0,2.9-1.4,3.5-3.7l1.4-7.1c0.1-0.4,0.4-0.7,0.8-0.7c2,0,2-0.6,2-3.5c-0.5-5.5-1.9-7.6-4-9.3c-0.1,0-0.1-0.1-0.1-0.2L60.2,54C60.2,54,58.2,54.6,57,54.6 M57,39.7c-4.7,0-8.6,3.8-8.6,8.6c0,1.6,0.5,3.2,1.3,4.5c-2.5,2.5-3.7,5.8-4.2,11.1l0,0.1l0,0.1c0,2.1,0,5.6,3.3,6.7l1.1,5.3l0,0l0,0c1,3.9,3.7,6.4,7,6.4c3.3,0,6.1-2.6,7.1-6.5l0,0l0,0l1-5.2c3.3-1.1,3.3-4.6,3.3-6.9l0-0.1l0-0.1c-0.4-5.1-1.7-8.4-4.2-10.9c0.9-1.4,1.3-2.9,1.3-4.5C65.6,43.5,61.7,39.7,57,39.7L57,39.7z M57,51.1c-1.6,0-2.9-1.3-2.9-2.9c0-1.6,1.3-2.9,2.9-2.9c1.6,0,2.9,1.3,2.9,2.9C59.9,49.8,58.6,51.1,57,51.1L57,51.1z M57,56.6c0.8,0,1.8-0.2,2.6-0.4c1.4,1.1,2.7,2.6,3.2,7.8c0,0.5,0,1,0,1.4c-1.3,0-2.5,1-2.8,2.3l-1.4,7c-0.3,1.3-1,2.1-1.5,2.1c-0.5,0-1.2-0.7-1.5-2l-1.4-7.1c-0.3-1.3-1.4-2.3-2.8-2.3c0-0.3,0-0.8,0-1.2c0.5-5.3,1.7-6.7,3.2-7.9C55.2,56.4,56.1,56.6,57,56.6L57,56.6z"/></g><path class="image-set-annotation-creator-crowd-sourced-st0" d="M60.2,54l0.4,0.5c0,0.1,0.1,0.1,0.1,0.2c2.1,1.7,3.5,3.8,4,9.3c0,2.9,0,3.5-2,3.5c-0.4,0-0.8,0.3-0.8,0.7l-1.4,7.1c-0.6,2.2-1.9,3.7-3.5,3.7c-1.6,0-2.9-1.4-3.4-3.6l-1.4-7.2c-0.1-0.4-0.4-0.7-0.8-0.7c-2,0-2-0.6-2-3.3c0.5-5.6,1.8-7.7,4-9.5c0.1,0,0.1-0.1,0.1-0.2l0.4-0.5c0,0,1.8,0.6,3.2,0.6C58.2,54.6,60.2,54,60.2,54z"/><circle class="image-set-annotation-creator-crowd-sourced-st0" cx="57" cy="48.3" r="4.9"/></g></g><g><g><polyline class="image-set-annotation-creator-crowd-sourced-st1" points="38.3,31.8 38.3,32.8 37.3,32.8 "/><line class="image-set-annotation-creator-crowd-sourced-st2" x1="35.4" y1="32.8" x2="6.2" y2="32.8"/><polyline class="image-set-annotation-creator-crowd-sourced-st1" points="5.3,32.8 4.3,32.8 4.3,31.8 "/><line class="image-set-annotation-creator-crowd-sourced-st3" x1="4.3" y1="29.7" x2="4.3" y2="6.4"/><polyline class="image-set-annotation-creator-crowd-sourced-st1" points="4.3,5.4 4.3,4.4 5.3,4.4 "/><line class="image-set-annotation-creator-crowd-sourced-st2" x1="7.2" y1="4.4" x2="36.4" y2="4.4"/><polyline class="image-set-annotation-creator-crowd-sourced-st1" points="37.3,4.4 38.3,4.4 38.3,5.4 "/><line class="image-set-annotation-creator-crowd-sourced-st3" x1="38.3" y1="7.4" x2="38.3" y2="30.7"/></g></g><g><path d="M24.4,53.3c-0.4,0-0.7-0.2-0.9-0.6l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.1,0.2,0.1,0.5,0,0.8s-0.3,0.4-0.5,0.6l-2.8,1.2C24.7,53.3,24.6,53.3,24.4,53.3z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M15.8,29.6l12.6,13.3l-5.1-0.2l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L15.8,29.6 M15.8,27.6c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2L15.5,48c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L17.3,28.2C16.9,27.8,16.4,27.6,15.8,27.6L15.8,27.6z"/></g><g><path class="image-set-annotation-creator-crowd-sourced-st4" d="M21.2,15.4c0,0.3-0.1,0.7-0.1,1c-0.1,0.9,0.2,1.7,0.6,2.6c0.4,0.8,0.6,1.6,0.6,2.4c0,0.9-0.3,1.8-0.7,2.6c-0.7,1.4-0.7,2.9-0.1,4.3c0.2,0.5,0.4,0.9,0.6,1.3c0.2,0.2,0.2,0.5,0.2,0.9"/><path class="image-set-annotation-creator-crowd-sourced-st4" d="M17.4,14.3c0.1,0.5-0.2,0.9-0.2,1.5c-0.2,1-0.1,2,0.4,3c0.3,0.6,0.6,1.3,0.7,2.1c0.2,0.9-0.1,1.7-0.4,2.6c-0.2,0.5-0.5,1.2-0.7,1.8c-0.2,0.8-0.2,1.6,0.1,2.3c0.1,0.2,0.1,0.5,0.1,0.7"/><path class="image-set-annotation-creator-crowd-sourced-st4" d="M25.4,14.3c0.1,0.4-0.1,0.8-0.2,1.2c-0.3,1.2-0.2,2.3,0.4,3.3c0.2,0.5,0.5,1.1,0.6,1.6c0.2,1.1,0.1,2.1-0.5,3.1c-0.4,0.7-0.6,1.5-0.7,2.3c-0.1,0.5,0.1,1,0.2,1.6c0.1,0.2,0.1,0.5,0.1,0.7"/><g><g><g><path d="M28,17.2c-0.7,0-1.3-0.2-1.8-0.7c-0.2-0.2-0.4-0.3-0.5-0.5c-0.1-0.1-0.2-0.1-0.3-0.1S25.1,16,25,16.1c-0.1,0.1-0.2,0.2-0.3,0.2c-0.5,0.4-1,0.6-1.6,0.6c-0.6,0-1.2-0.2-1.7-0.8c-0.2-0.2-0.4-0.4-0.5-0.4c-0.1,0-0.2,0.1-0.5,0.2c-0.5,0.3-0.9,0.5-1.4,0.5c-0.5,0-0.9-0.2-1.2-0.4c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.6,0.1-0.9,0.4c-0.5,0.4-1,0.5-1.7,0.5c-0.2,0-0.5,0-0.9-0.1c-0.5-0.1-0.8-0.4-0.9-0.9c-0.1-0.2-0.1-0.4-0.2-0.6l-0.1-0.3v-0.1c0.2-2.2,1.1-3.8,2.4-5.1c1.4-1.3,3.1-2.2,5.1-2.5c0.6-0.1,1.2-0.2,1.7-0.2c1.9,0,3.7,0.5,5.4,1.6c1.9,1.2,3,2.8,3.3,4.8c0.2,0.7,0.2,1.4,0.1,2.2c-0.2,0.7-0.6,1.2-1.2,1.3C28.6,17.1,28.3,17.2,28,17.2z"/><path class="image-set-annotation-creator-crowd-sourced-st0" d="M21.3,7.5c1.8,0,3.6,0.5,5.1,1.6c1.6,1.1,2.8,2.6,3.2,4.6c0.2,0.7,0.2,1.3,0.1,2c-0.2,0.5-0.5,0.9-1,1c-0.3,0.1-0.5,0.1-0.8,0.1c-0.5,0-1.1-0.2-1.6-0.6c-0.2-0.2-0.4-0.3-0.6-0.5c-0.2-0.2-0.4-0.2-0.5-0.2c-0.2,0-0.4,0.1-0.5,0.2c-0.1,0.1-0.2,0.2-0.3,0.2c-0.4,0.3-0.9,0.5-1.3,0.5c-0.5,0-1.1-0.2-1.5-0.6c-0.3-0.3-0.5-0.5-0.8-0.5c-0.2,0-0.5,0.1-0.7,0.3c-0.4,0.3-0.8,0.5-1.2,0.5c-0.4,0-0.7-0.1-1.1-0.3s-0.7-0.3-1.1-0.3S16,15.7,15.6,16c-0.5,0.3-0.9,0.5-1.5,0.5c-0.3,0-0.5,0-0.9-0.1c-0.3-0.1-0.5-0.2-0.6-0.5c-0.1-0.3-0.1-0.5-0.2-0.9c0.2-1.9,0.9-3.6,2.3-4.9c1.4-1.3,3-2.1,4.9-2.3C20.2,7.5,20.8,7.5,21.3,7.5 M21.3,6.8L21.3,6.8c-0.6,0-1.2,0.1-1.8,0.2c-2.1,0.3-3.9,1.2-5.3,2.6s-2.3,3.1-2.5,5.4V15v0.2l0.1,0.2c0,0.2,0.1,0.4,0.2,0.6c0.2,0.6,0.6,1,1.2,1.1c0.4,0.1,0.7,0.1,1,0.1c0.8,0,1.4-0.2,1.9-0.6c0.3-0.2,0.5-0.3,0.7-0.3c0.2,0,0.4,0.1,0.7,0.2c0.5,0.3,1,0.5,1.5,0.5c0.6,0,1.2-0.2,1.6-0.6c0.2-0.1,0.2-0.2,0.2-0.2c0.1,0,0.2,0.1,0.2,0.2c0.5,0.5,1.2,0.9,2,0.9c0.7,0,1.3-0.2,1.9-0.7c0.1-0.1,0.2-0.2,0.2-0.2c0.1-0.1,0.2-0.1,0.2-0.1s0.1,0,0.1,0.1c0.2,0.1,0.3,0.2,0.5,0.4c0.6,0.5,1.3,0.8,2.1,0.8c0.3,0,0.6-0.1,1-0.2c0.8-0.2,1.3-0.8,1.6-1.6c0.2-0.9,0.1-1.7-0.1-2.4c-0.4-2.1-1.6-3.8-3.6-5.1C25.2,7.3,23.3,6.8,21.3,6.8L21.3,6.8z"/></g></g></g></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-creator_expert.svg b/docs/ifdos/svgs/image-annotation-creator_expert.svg deleted file mode 100644 index 016fd87edb8f61844bb0da94a5c0e7df4b45fcae..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-creator_expert.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-creator_expert" alt="image-set-annotation-creator is expert" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-creator is expert</title><style type="text/css">.image-set-annotation-creator-expert-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-creator-expert-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.8833,1.8833;}.image-set-annotation-creator-expert-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0267,2.0267;}.image-set-annotation-creator-expert-st3{stroke:#FFFFFF;stroke-miterlimit:10;}.image-set-annotation-creator-expert-st4{stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-creator-expert-st5{fill:#FFFFFF;}.image-set-annotation-creator-expert-st6{fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-creator-expert-st0" points="38.3,31.8 38.3,32.8 37.3,32.8 "/><line class="image-set-annotation-creator-expert-st1" x1="35.4" y1="32.8" x2="6.2" y2="32.8"/><polyline class="image-set-annotation-creator-expert-st0" points="5.3,32.8 4.3,32.8 4.3,31.8 "/><line class="image-set-annotation-creator-expert-st2" x1="4.3" y1="29.7" x2="4.3" y2="6.4"/><polyline class="image-set-annotation-creator-expert-st0" points="4.3,5.4 4.3,4.4 5.3,4.4 "/><line class="image-set-annotation-creator-expert-st1" x1="7.2" y1="4.4" x2="36.4" y2="4.4"/><polyline class="image-set-annotation-creator-expert-st0" points="37.3,4.4 38.3,4.4 38.3,5.4 "/><line class="image-set-annotation-creator-expert-st2" x1="38.3" y1="7.4" x2="38.3" y2="30.7"/></g></g><path class="image-set-annotation-creator-expert-st3" d="M63.3,8.9c-6.7,0-12.1,5.4-12.1,12.1c0,2.9,1.1,5.8,3.1,8l0.7,0.8l-0.9,0.7c-5.1,4.2-7.4,9.7-8.3,19.6c0,5.1,0.3,8.5,4.8,9.3l0.7,0.1l2.4,12.1c1.4,5.5,5.1,9.1,9.4,9.1c4.4,0,8.1-3.6,9.5-9.2l2.4-11.9l0.7-0.1c4.5-0.8,4.8-4.1,4.8-9.6c-0.8-9.6-3.1-15.1-8.3-19.3l-0.9-0.7l0.7-0.8c2-2.2,3.1-5.1,3.1-8C75.5,14.3,70,8.9,63.3,8.9z M69.3,31.6l0.7,0.9c0.1,0.1,0.2,0.2,0.3,0.3c3.9,3.1,6.5,7.1,7.3,17.2c0,5.4,0,6.5-3.7,6.5c-0.7,0-1.4,0.5-1.5,1.3l-2.6,13.1c-1,4.1-3.6,6.8-6.4,6.8c-2.9,0-5.4-2.6-6.4-6.6l-2.7-13.3c-0.1-0.7-0.8-1.3-1.5-1.3c-3.7,0-3.7-1.2-3.7-6.1c0.9-10.4,3.4-14.3,7.4-17.5c0.1-0.1,0.2-0.2,0.3-0.3l0.7-0.9c0,0,3.3,1.2,5.9,1.2C65.6,32.7,69.3,31.6,69.3,31.6z M63.3,30c-5,0-9-4-9-9s4-9,9-9s9,4,9,9S68.3,30,63.3,30z"/><polygon class="image-set-annotation-creator-expert-st4" points="63.3,35.6 66.3,41.6 72.8,42.5 68.1,47.1 69.2,53.7 63.3,50.6 57.4,53.7 58.6,47.1 53.8,42.5 60.4,41.6 "/><g><path d="M24.4,53.3c-0.4,0-0.7-0.2-0.9-0.6l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.1,0.2,0.1,0.5,0,0.8s-0.3,0.4-0.5,0.6l-2.8,1.2C24.7,53.3,24.6,53.3,24.4,53.3z"/><path class="image-set-annotation-creator-expert-st5" d="M15.8,29.6l12.6,13.3l-5.1-0.2l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L15.8,29.6 M15.8,27.6c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2L15.5,48c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L17.3,28.2C16.9,27.8,16.4,27.6,15.8,27.6L15.8,27.6z"/></g><g><path class="image-set-annotation-creator-expert-st6" d="M21.2,15.4c0,0.3-0.1,0.7-0.1,1c-0.1,0.9,0.2,1.7,0.6,2.6c0.4,0.8,0.6,1.6,0.6,2.4c0,0.9-0.3,1.8-0.7,2.6c-0.7,1.4-0.7,2.9-0.1,4.3c0.2,0.5,0.4,0.9,0.6,1.3c0.2,0.2,0.2,0.5,0.2,0.9"/><path class="image-set-annotation-creator-expert-st6" d="M17.4,14.3c0.1,0.5-0.2,0.9-0.2,1.5c-0.2,1-0.1,2,0.4,3c0.3,0.6,0.6,1.3,0.7,2.1c0.2,0.9-0.1,1.7-0.4,2.6c-0.2,0.5-0.5,1.2-0.7,1.8c-0.2,0.8-0.2,1.6,0.1,2.3c0.1,0.2,0.1,0.5,0.1,0.7"/><path class="image-set-annotation-creator-expert-st6" d="M25.4,14.3c0.1,0.4-0.1,0.8-0.2,1.2c-0.3,1.2-0.2,2.3,0.4,3.3c0.2,0.5,0.5,1.1,0.6,1.6c0.2,1.1,0.1,2.1-0.5,3.1c-0.4,0.7-0.6,1.5-0.7,2.3c-0.1,0.5,0.1,1,0.2,1.6c0.1,0.2,0.1,0.5,0.1,0.7"/><g><g><g><path d="M28,17.2c-0.7,0-1.3-0.2-1.8-0.7c-0.2-0.2-0.4-0.3-0.5-0.5c-0.1-0.1-0.2-0.1-0.3-0.1S25.1,16,25,16.1c-0.1,0.1-0.2,0.2-0.3,0.2c-0.5,0.4-1,0.6-1.6,0.6c-0.6,0-1.2-0.2-1.7-0.8c-0.2-0.2-0.4-0.4-0.5-0.4c-0.1,0-0.2,0.1-0.5,0.2c-0.5,0.3-0.9,0.5-1.4,0.5c-0.5,0-0.9-0.2-1.2-0.4c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.6,0.1-0.9,0.4c-0.5,0.4-1,0.5-1.7,0.5c-0.2,0-0.5,0-0.9-0.1c-0.5-0.1-0.8-0.4-0.9-0.9c-0.1-0.2-0.1-0.4-0.2-0.6l-0.1-0.3v-0.1c0.2-2.2,1.1-3.8,2.4-5.1c1.4-1.3,3.1-2.2,5.1-2.5c0.6-0.1,1.2-0.2,1.7-0.2c1.9,0,3.7,0.5,5.4,1.6c1.9,1.2,3,2.8,3.3,4.8c0.2,0.7,0.2,1.4,0.1,2.2c-0.2,0.7-0.6,1.2-1.2,1.3C28.6,17.1,28.3,17.2,28,17.2z"/><path class="image-set-annotation-creator-expert-st5" d="M21.3,7.5c1.8,0,3.6,0.5,5.1,1.6c1.6,1.1,2.8,2.6,3.2,4.6c0.2,0.7,0.2,1.3,0.1,2c-0.2,0.5-0.5,0.9-1,1c-0.3,0.1-0.5,0.1-0.8,0.1c-0.5,0-1.1-0.2-1.6-0.6c-0.2-0.2-0.4-0.3-0.6-0.5c-0.2-0.2-0.4-0.2-0.5-0.2c-0.2,0-0.4,0.1-0.5,0.2c-0.1,0.1-0.2,0.2-0.3,0.2c-0.4,0.3-0.9,0.5-1.3,0.5c-0.5,0-1.1-0.2-1.5-0.6c-0.3-0.3-0.5-0.5-0.8-0.5c-0.2,0-0.5,0.1-0.7,0.3c-0.4,0.3-0.8,0.5-1.2,0.5c-0.4,0-0.7-0.1-1.1-0.3s-0.7-0.3-1.1-0.3S16,15.7,15.6,16c-0.5,0.3-0.9,0.5-1.5,0.5c-0.3,0-0.5,0-0.9-0.1c-0.3-0.1-0.5-0.2-0.6-0.5c-0.1-0.3-0.1-0.5-0.2-0.9c0.2-1.9,0.9-3.6,2.3-4.9c1.4-1.3,3-2.1,4.9-2.3C20.2,7.5,20.8,7.5,21.3,7.5 M21.3,6.8L21.3,6.8c-0.6,0-1.2,0.1-1.8,0.2c-2.1,0.3-3.9,1.2-5.3,2.6s-2.3,3.1-2.5,5.4V15v0.2l0.1,0.2c0,0.2,0.1,0.4,0.2,0.6c0.2,0.6,0.6,1,1.2,1.1c0.4,0.1,0.7,0.1,1,0.1c0.8,0,1.4-0.2,1.9-0.6c0.3-0.2,0.5-0.3,0.7-0.3c0.2,0,0.4,0.1,0.7,0.2c0.5,0.3,1,0.5,1.5,0.5c0.6,0,1.2-0.2,1.6-0.6c0.2-0.1,0.2-0.2,0.2-0.2c0.1,0,0.2,0.1,0.2,0.2c0.5,0.5,1.2,0.9,2,0.9c0.7,0,1.3-0.2,1.9-0.7c0.1-0.1,0.2-0.2,0.2-0.2c0.1-0.1,0.2-0.1,0.2-0.1s0.1,0,0.1,0.1c0.2,0.1,0.3,0.2,0.5,0.4c0.6,0.5,1.3,0.8,2.1,0.8c0.3,0,0.6-0.1,1-0.2c0.8-0.2,1.3-0.8,1.6-1.6c0.2-0.9,0.1-1.7-0.1-2.4c-0.4-2.1-1.6-3.8-3.6-5.1C25.2,7.3,23.3,6.8,21.3,6.8L21.3,6.8z"/></g></g></g></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-creator_non-expert.svg b/docs/ifdos/svgs/image-annotation-creator_non-expert.svg deleted file mode 100644 index bef429d195cbe8f9e0a084b0d29405f0abe8ce88..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-creator_non-expert.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-creator_non-expert" alt="image-set-annotation-creator is non-expert" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-creator is non-expert</title><style type="text/css">.image-set-annotation-creator-non-expert-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-creator-non-expert-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.8833,1.8833;}.image-set-annotation-creator-non-expert-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0267,2.0267;}.image-set-annotation-creator-non-expert-st3{stroke:#FFFFFF;stroke-miterlimit:10;}.image-set-annotation-creator-non-expert-st4{fill:#FFFFFF;}.image-set-annotation-creator-non-expert-st5{fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-creator-non-expert-st0" points="38.3,31.8 38.3,32.8 37.3,32.8 "/><line class="image-set-annotation-creator-non-expert-st1" x1="35.4" y1="32.8" x2="6.2" y2="32.8"/><polyline class="image-set-annotation-creator-non-expert-st0" points="5.3,32.8 4.3,32.8 4.3,31.8 "/><line class="image-set-annotation-creator-non-expert-st2" x1="4.3" y1="29.7" x2="4.3" y2="6.4"/><polyline class="image-set-annotation-creator-non-expert-st0" points="4.3,5.4 4.3,4.4 5.3,4.4 "/><line class="image-set-annotation-creator-non-expert-st1" x1="7.2" y1="4.4" x2="36.4" y2="4.4"/><polyline class="image-set-annotation-creator-non-expert-st0" points="37.3,4.4 38.3,4.4 38.3,5.4 "/><line class="image-set-annotation-creator-non-expert-st2" x1="38.3" y1="7.4" x2="38.3" y2="30.7"/></g></g><path class="image-set-annotation-creator-non-expert-st3" d="M63.3,8.9c-6.7,0-12.1,5.4-12.1,12.1c0,2.9,1.1,5.8,3.1,8l0.7,0.8l-0.9,0.7c-5.1,4.2-7.4,9.7-8.3,19.6c0,5.1,0.3,8.5,4.8,9.3l0.7,0.1l2.4,12.1c1.4,5.5,5.1,9.1,9.4,9.1c4.4,0,8.1-3.6,9.5-9.2l2.4-11.9l0.7-0.1c4.5-0.8,4.8-4.1,4.8-9.6c-0.8-9.6-3.1-15.1-8.3-19.3l-0.9-0.7l0.7-0.8c2-2.2,3.1-5.1,3.1-8C75.5,14.3,70,8.9,63.3,8.9z M69.3,31.6l0.7,0.9c0.1,0.1,0.2,0.2,0.3,0.3c3.9,3.1,6.5,7.1,7.3,17.2c0,5.4,0,6.5-3.7,6.5c-0.7,0-1.4,0.5-1.5,1.3l-2.6,13.1c-1,4.1-3.6,6.8-6.4,6.8c-2.9,0-5.4-2.6-6.4-6.6l-2.7-13.3c-0.1-0.7-0.8-1.3-1.5-1.3c-3.7,0-3.7-1.2-3.7-6.1c0.9-10.4,3.4-14.3,7.4-17.5c0.1-0.1,0.2-0.2,0.3-0.3l0.7-0.9c0,0,3.3,1.2,5.9,1.2C65.6,32.7,69.3,31.6,69.3,31.6z M63.3,30c-5,0-9-4-9-9s4-9,9-9s9,4,9,9S68.3,30,63.3,30z"/><polygon class="image-set-annotation-creator-non-expert-st0" points="63.3,35.6 66.3,41.6 72.8,42.5 68.1,47.1 69.2,53.7 63.3,50.6 57.4,53.7 58.6,47.1 53.8,42.5 60.4,41.6 "/><g><path d="M24.4,53.3c-0.4,0-0.7-0.2-0.9-0.6l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.1,0.2,0.1,0.5,0,0.8s-0.3,0.4-0.5,0.6l-2.8,1.2C24.7,53.3,24.6,53.3,24.4,53.3z"/><path class="image-set-annotation-creator-non-expert-st4" d="M15.8,29.6l12.6,13.3l-5.1-0.2l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L15.8,29.6 M15.8,27.6c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2L15.5,48c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L17.3,28.2C16.9,27.8,16.4,27.6,15.8,27.6L15.8,27.6z"/></g><g><path class="image-set-annotation-creator-non-expert-st5" d="M21.2,15.4c0,0.3-0.1,0.7-0.1,1c-0.1,0.9,0.2,1.7,0.6,2.6c0.4,0.8,0.6,1.6,0.6,2.4c0,0.9-0.3,1.8-0.7,2.6c-0.7,1.4-0.7,2.9-0.1,4.3c0.2,0.5,0.4,0.9,0.6,1.3c0.2,0.2,0.2,0.5,0.2,0.9"/><path class="image-set-annotation-creator-non-expert-st5" d="M17.4,14.3c0.1,0.5-0.2,0.9-0.2,1.5c-0.2,1-0.1,2,0.4,3c0.3,0.6,0.6,1.3,0.7,2.1c0.2,0.9-0.1,1.7-0.4,2.6c-0.2,0.5-0.5,1.2-0.7,1.8c-0.2,0.8-0.2,1.6,0.1,2.3c0.1,0.2,0.1,0.5,0.1,0.7"/><path class="image-set-annotation-creator-non-expert-st5" d="M25.4,14.3c0.1,0.4-0.1,0.8-0.2,1.2c-0.3,1.2-0.2,2.3,0.4,3.3c0.2,0.5,0.5,1.1,0.6,1.6c0.2,1.1,0.1,2.1-0.5,3.1c-0.4,0.7-0.6,1.5-0.7,2.3c-0.1,0.5,0.1,1,0.2,1.6c0.1,0.2,0.1,0.5,0.1,0.7"/><g><g><g><path d="M28,17.2c-0.7,0-1.3-0.2-1.8-0.7c-0.2-0.2-0.4-0.3-0.5-0.5c-0.1-0.1-0.2-0.1-0.3-0.1S25.1,16,25,16.1c-0.1,0.1-0.2,0.2-0.3,0.2c-0.5,0.4-1,0.6-1.6,0.6c-0.6,0-1.2-0.2-1.7-0.8c-0.2-0.2-0.4-0.4-0.5-0.4c-0.1,0-0.2,0.1-0.5,0.2c-0.5,0.3-0.9,0.5-1.4,0.5c-0.5,0-0.9-0.2-1.2-0.4c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.6,0.1-0.9,0.4c-0.5,0.4-1,0.5-1.7,0.5c-0.2,0-0.5,0-0.9-0.1c-0.5-0.1-0.8-0.4-0.9-0.9c-0.1-0.2-0.1-0.4-0.2-0.6l-0.1-0.3v-0.1c0.2-2.2,1.1-3.8,2.4-5.1c1.4-1.3,3.1-2.2,5.1-2.5c0.6-0.1,1.2-0.2,1.7-0.2c1.9,0,3.7,0.5,5.4,1.6c1.9,1.2,3,2.8,3.3,4.8c0.2,0.7,0.2,1.4,0.1,2.2c-0.2,0.7-0.6,1.2-1.2,1.3C28.6,17.1,28.3,17.2,28,17.2z"/><path class="image-set-annotation-creator-non-expert-st4" d="M21.3,7.5c1.8,0,3.6,0.5,5.1,1.6c1.6,1.1,2.8,2.6,3.2,4.6c0.2,0.7,0.2,1.3,0.1,2c-0.2,0.5-0.5,0.9-1,1c-0.3,0.1-0.5,0.1-0.8,0.1c-0.5,0-1.1-0.2-1.6-0.6c-0.2-0.2-0.4-0.3-0.6-0.5c-0.2-0.2-0.4-0.2-0.5-0.2c-0.2,0-0.4,0.1-0.5,0.2c-0.1,0.1-0.2,0.2-0.3,0.2c-0.4,0.3-0.9,0.5-1.3,0.5c-0.5,0-1.1-0.2-1.5-0.6c-0.3-0.3-0.5-0.5-0.8-0.5c-0.2,0-0.5,0.1-0.7,0.3c-0.4,0.3-0.8,0.5-1.2,0.5c-0.4,0-0.7-0.1-1.1-0.3s-0.7-0.3-1.1-0.3S16,15.7,15.6,16c-0.5,0.3-0.9,0.5-1.5,0.5c-0.3,0-0.5,0-0.9-0.1c-0.3-0.1-0.5-0.2-0.6-0.5c-0.1-0.3-0.1-0.5-0.2-0.9c0.2-1.9,0.9-3.6,2.3-4.9c1.4-1.3,3-2.1,4.9-2.3C20.2,7.5,20.8,7.5,21.3,7.5 M21.3,6.8L21.3,6.8c-0.6,0-1.2,0.1-1.8,0.2c-2.1,0.3-3.9,1.2-5.3,2.6s-2.3,3.1-2.5,5.4V15v0.2l0.1,0.2c0,0.2,0.1,0.4,0.2,0.6c0.2,0.6,0.6,1,1.2,1.1c0.4,0.1,0.7,0.1,1,0.1c0.8,0,1.4-0.2,1.9-0.6c0.3-0.2,0.5-0.3,0.7-0.3c0.2,0,0.4,0.1,0.7,0.2c0.5,0.3,1,0.5,1.5,0.5c0.6,0,1.2-0.2,1.6-0.6c0.2-0.1,0.2-0.2,0.2-0.2c0.1,0,0.2,0.1,0.2,0.2c0.5,0.5,1.2,0.9,2,0.9c0.7,0,1.3-0.2,1.9-0.7c0.1-0.1,0.2-0.2,0.2-0.2c0.1-0.1,0.2-0.1,0.2-0.1s0.1,0,0.1,0.1c0.2,0.1,0.3,0.2,0.5,0.4c0.6,0.5,1.3,0.8,2.1,0.8c0.3,0,0.6-0.1,1-0.2c0.8-0.2,1.3-0.8,1.6-1.6c0.2-0.9,0.1-1.7-0.1-2.4c-0.4-2.1-1.6-3.8-3.6-5.1C25.2,7.3,23.3,6.8,21.3,6.8L21.3,6.8z"/></g></g></g></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-labels_biology.svg b/docs/ifdos/svgs/image-annotation-labels_biology.svg deleted file mode 100644 index 3849dafc8a47bb636ff875d811dac8c158c14e31..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-labels_biology.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-labels_biology" alt="image-set-annotation-labels is biology" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-labels is biology</title><style type="text/css">.image-set-annotation-labels-biology-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-labels-biology-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0119,2.0119;}.image-set-annotation-labels-biology-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.9682,1.9682;}.image-set-annotation-labels-biology-st3{fill:#FFFFFF;}.image-set-annotation-labels-biology-st4{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-labels-biology-st0" points="80.7,64.7 80.7,65.7 79.7,65.7 "/><line class="image-set-annotation-labels-biology-st1" x1="77.7" y1="65.7" x2="6.3" y2="65.7"/><polyline class="image-set-annotation-labels-biology-st0" points="5.3,65.7 4.3,65.7 4.3,64.7 "/><line class="image-set-annotation-labels-biology-st2" x1="4.3" y1="62.7" x2="4.3" y2="12.5"/><polyline class="image-set-annotation-labels-biology-st0" points="4.3,11.5 4.3,10.5 5.3,10.5 "/><line class="image-set-annotation-labels-biology-st1" x1="7.3" y1="10.5" x2="78.7" y2="10.5"/><polyline class="image-set-annotation-labels-biology-st0" points="79.7,10.5 80.7,10.5 80.7,11.5 "/><line class="image-set-annotation-labels-biology-st2" x1="80.7" y1="13.5" x2="80.7" y2="63.7"/></g></g><g><path d="M72.1,84.7c-0.1,0-0.2,0-0.4-0.1c-0.2-0.1-0.4-0.3-0.6-0.5l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.2,0.5,0,1.1-0.5,1.3l-2.8,1.2C72.4,84.7,72.3,84.7,72.1,84.7z"/><path class="image-set-annotation-labels-biology-st3" d="M63.6,61l12.6,13.3L71.1,74l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L63.6,61 M63.6,59c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2l1.6,18.2c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L65,59.6C64.6,59.2,64.1,59,63.6,59L63.6,59z"/></g><path class="image-set-annotation-labels-biology-st4" d="M41.7,32.3c0,0.6-0.1,1.3-0.1,1.8c-0.1,1.7,0.4,3.1,1.1,4.7c0.7,1.4,1.1,2.8,1.1,4.4c0,1.7-0.6,3.2-1.3,4.7c-1.3,2.5-1.3,5.2-0.1,7.8c0.3,0.8,0.7,1.6,1.1,2.4c0.3,0.4,0.4,1,0.3,1.6"/><path class="image-set-annotation-labels-biology-st4" d="M34.9,30.3c0.1,1-0.3,1.7-0.4,2.7c-0.3,1.8-0.1,3.7,0.7,5.5c0.6,1.1,1.1,2.4,1.3,3.8c0.3,1.7-0.1,3.1-0.7,4.7c-0.4,1-1,2.1-1.3,3.2c-0.3,1.4-0.3,2.8,0.1,4.1c0.1,0.4,0.1,0.8,0.1,1.3"/><path class="image-set-annotation-labels-biology-st4" d="M49.3,30.3c0.1,0.7-0.1,1.4-0.3,2.1c-0.6,2.1-0.3,4.1,0.7,6.1c0.4,1,1,2,1.1,3c0.4,2,0.1,3.8-0.8,5.7c-0.7,1.3-1.1,2.7-1.3,4.1c-0.1,1,0.1,1.8,0.3,2.8c0.1,0.4,0.1,0.8,0.1,1.3"/><g><g><g><path d="M54.1,35.6c-1.3,0-2.4-0.4-3.2-1.3c-0.3-0.3-0.7-0.6-1-0.8c-0.1-0.1-0.4-0.1-0.6-0.1c-0.1,0-0.4,0.1-0.7,0.3c-0.1,0.1-0.3,0.3-0.6,0.4c-0.8,0.7-1.8,1.1-3,1.1c-1.1,0-2.3-0.4-3.1-1.4c-0.4-0.4-0.7-0.7-1-0.7c-0.1,0-0.4,0.1-0.8,0.4c-0.8,0.6-1.7,1-2.5,1c-0.8,0-1.6-0.3-2.3-0.7c-0.6-0.3-1.1-0.6-1.6-0.6c-0.6,0-1.1,0.1-1.7,0.7c-0.8,0.7-1.8,1-3.1,1c-0.4,0-1,0-1.7-0.1c-0.8-0.1-1.4-0.7-1.7-1.6c-0.1-0.4-0.1-0.7-0.3-1.1l-0.1-0.6v-0.1c0.4-4,2-6.9,4.4-9.3c2.5-2.4,5.7-4,9.3-4.5c1.1-0.1,2.1-0.3,3.1-0.3c3.5,0,6.8,1,9.7,2.8c3.4,2.1,5.5,5.1,6.1,8.8c0.3,1.3,0.4,2.5,0.1,4c-0.3,1.3-1.1,2.1-2.3,2.4C55.1,35.4,54.5,35.6,54.1,35.6z"/><path class="image-set-annotation-labels-biology-st3" d="M42,18c3.2,0,6.5,0.8,9.3,2.8c3,2,5.1,4.7,5.8,8.3c0.3,1.3,0.4,2.4,0.1,3.7c-0.3,1-0.8,1.6-1.8,1.8c-0.6,0.1-1,0.1-1.4,0.1c-1,0-2-0.3-2.8-1.1c-0.3-0.3-0.7-0.6-1.1-0.8c-0.3-0.3-0.7-0.3-1-0.3c-0.3,0-0.7,0.1-1,0.3c-0.1,0.1-0.4,0.3-0.6,0.4c-0.7,0.6-1.6,1-2.4,1c-1,0-2-0.4-2.7-1.1c-0.6-0.6-1-0.8-1.4-0.8s-0.8,0.1-1.3,0.6c-0.7,0.6-1.4,0.8-2.1,0.8c-0.7,0-1.3-0.1-2-0.6c-0.7-0.4-1.3-0.6-2-0.6s-1.4,0.3-2.1,0.8c-0.8,0.6-1.7,0.8-2.7,0.8c-0.6,0-1,0-1.6-0.1c-0.6-0.1-1-0.4-1.1-1c-0.1-0.6-0.1-1-0.3-1.6c0.4-3.4,1.7-6.5,4.1-8.9c2.5-2.4,5.5-3.8,8.9-4.2C40,18,41,18,42,18 M42,16.6L42,16.6c-1.1,0-2.1,0.1-3.2,0.3c-3.8,0.6-7.1,2.1-9.6,4.7s-4.1,5.7-4.5,9.7v0.3v0.3l0.1,0.4c0,0.4,0.1,0.7,0.3,1.1c0.3,1.1,1.1,1.8,2.3,2c0.7,0.1,1.3,0.1,1.8,0.1c1.4,0,2.5-0.4,3.5-1.1c0.6-0.4,1-0.6,1.3-0.6c0.3,0,0.7,0.1,1.3,0.4c0.8,0.6,1.8,0.8,2.7,0.8c1.1,0,2.1-0.4,3-1.1c0.3-0.1,0.4-0.3,0.4-0.3c0.1,0,0.3,0.1,0.4,0.4c1,1,2.3,1.6,3.7,1.6c1.3,0,2.4-0.4,3.4-1.3c0.1-0.1,0.3-0.3,0.4-0.3c0.1-0.1,0.3-0.1,0.3-0.1s0.1,0,0.1,0.1c0.3,0.1,0.6,0.4,1,0.7c1.1,1,2.4,1.4,3.8,1.4c0.6,0,1.1-0.1,1.8-0.3c1.4-0.4,2.4-1.4,2.8-2.8c0.4-1.6,0.1-3.1-0.1-4.4c-0.7-3.8-3-6.9-6.5-9.2C49,17.6,45.6,16.6,42,16.6L42,16.6z"/></g></g></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-labels_garbage.svg b/docs/ifdos/svgs/image-annotation-labels_garbage.svg deleted file mode 100644 index c3b1e5c61212540c8c4fc8445ed0db756e2a4bd3..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-labels_garbage.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-labels_garbage" alt="image-set-annotation-labels is garbage" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-labels is garbage</title><style type="text/css">.image-set-annotation-labels-garbage-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-labels-garbage-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0119,2.0119;}.image-set-annotation-labels-garbage-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.9682,1.9682;}.image-set-annotation-labels-garbage-st3{fill:#FFFFFF;}.image-set-annotation-labels-garbage-st4{fill:none;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}.image-set-annotation-labels-garbage-st5{stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}.image-set-annotation-labels-garbage-st6{fill:#FFFFFF;stroke:#000000;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-labels-garbage-st0" points="80.7,64.7 80.7,65.7 79.7,65.7 "/><line class="image-set-annotation-labels-garbage-st1" x1="77.7" y1="65.7" x2="6.3" y2="65.7"/><polyline class="image-set-annotation-labels-garbage-st0" points="5.3,65.7 4.3,65.7 4.3,64.7 "/><line class="image-set-annotation-labels-garbage-st2" x1="4.3" y1="62.7" x2="4.3" y2="12.5"/><polyline class="image-set-annotation-labels-garbage-st0" points="4.3,11.5 4.3,10.5 5.3,10.5 "/><line class="image-set-annotation-labels-garbage-st1" x1="7.3" y1="10.5" x2="78.7" y2="10.5"/><polyline class="image-set-annotation-labels-garbage-st0" points="79.7,10.5 80.7,10.5 80.7,11.5 "/><line class="image-set-annotation-labels-garbage-st2" x1="80.7" y1="13.5" x2="80.7" y2="63.7"/></g></g><g><path d="M72.1,84.7c-0.1,0-0.2,0-0.4-0.1c-0.2-0.1-0.4-0.3-0.6-0.5l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.2,0.5,0,1.1-0.5,1.3l-2.8,1.2C72.4,84.7,72.3,84.7,72.1,84.7z"/><path class="image-set-annotation-labels-garbage-st3" d="M63.6,61l12.6,13.3L71.1,74l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L63.6,61 M63.6,59c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2l1.6,18.2c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L65,59.6C64.6,59.2,64.1,59,63.6,59L63.6,59z"/></g><line class="image-set-annotation-labels-garbage-st4" x1="15" y1="23.3" x2="29.2" y2="21.9"/><g><polygon class="image-set-annotation-labels-garbage-st4" points="70.6,40.4 61.5,38.9 63.5,21 74.4,22.8 "/><polygon class="image-set-annotation-labels-garbage-st5" points="75.4,21.1 63.1,19.1 61.7,22.8 75.5,25 "/><rect x="63.9" y="17.7" transform="matrix(0.9872 0.1595 -0.1595 0.9872 3.9041 -10.8288)" class="image-set-annotation-labels-garbage-st6" width="11" height="2.4"/></g><g><path class="image-set-annotation-labels-garbage-st5" d="M42.9,40.1l-3.8,17c0,0,0,0,0,0.1c-0.3,1.3,2.8,3.1,6.8,4c4.1,0.9,7.6,0.6,7.9-0.7l3.8-17L42.9,40.1z"/><ellipse transform="matrix(0.2544 -0.9671 0.9671 0.2544 -3.1001 79.8215)" class="image-set-annotation-labels-garbage-st6" cx="50.2" cy="41.9" rx="2.4" ry="7.5"/><ellipse transform="matrix(0.6773 -0.7357 0.7357 0.6773 -11.7826 50.6568)" class="image-set-annotation-labels-garbage-st5" cx="51.8" cy="38.8" rx="2.4" ry="7.5"/></g><g><path class="image-set-annotation-labels-garbage-st4" d="M30,15.6c-0.8,0.1-1.3,0.8-1.3,1.6l0.7,7.1c0.1,0.8-0.5,1.5-1.3,1.6l-11.4,1.1c-0.8,0.1-1.5-0.5-1.6-1.3l-0.7-7.1c-0.1-0.8-0.8-1.3-1.6-1.3l-1.8,0.2c-0.8,0.1-1.3,0.8-1.3,1.6l2.6,25.8c0.1,0.8,0.8,1.3,1.6,1.3l20.6-2c0.8-0.1,1.3-0.8,1.3-1.6l-2.6-25.8c-0.1-0.8-0.8-1.3-1.6-1.3L30,15.6z"/></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-labels_geology.svg b/docs/ifdos/svgs/image-annotation-labels_geology.svg deleted file mode 100644 index bb6381b3024a7ac02ddeaae646d0468c4aae878c..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-labels_geology.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-labels_geology" alt="image-set-annotation-labels is geology" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-labels is geology</title><style type="text/css">.image-set-annotation-labels-geology-st0{clip-path:url(#SGVIDimage-set-annotation-labelsgeology_2_);}.image-set-annotation-labels-geology-st1{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-labels-geology-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0119,2.0119;}.image-set-annotation-labels-geology-st3{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.9682,1.9682;}.image-set-annotation-labels-geology-st4{fill:#FFFFFF;}</style><g><defs><rect id="SGVIDimage-set-annotation-labelsgeology_1_" x="4.3" y="10.5" width="76.5" height="55.1"/></defs><clipPath id="SGVIDimage-set-annotation-labelsgeology_2_"><use xlink:href="#SGVIDimage-set-annotation-labelsgeology_1_" style="overflow:visible;"/></clipPath><g class="image-set-annotation-labels-geology-st0"><path d="M-2.5,37.4c14.5,0,29.2,0,43.7,0c0.2,0,0.4,0,0.6,0c0.4,0.1,0.8,0,1.2,0c14.5,0,29.2,0,43.7,0c0.8-0.1,1.7,0.2,1.7-1c0-0.9,0.2-1.9-1.3-1.8c-0.2,0-0.4,0-0.6-0.1c-1.7-1.6-3.4-3.1-5.1-4.8c1.9-0.3,3.1-0.1,4.1,1.1c0.8,1,1.8,1.8,2.9,2.8c0-0.6,0.1-0.9,0-1.1c-0.6-0.8-1.3-1.7-2-2.6c0.2-0.1,0.3-0.2,0.2-0.7c1.5-0.2,2-1.3,1.5-2.6c-0.2-0.4-0.2-1.1-0.2-1.7c0.1-0.4,0.3-1,0.4-1.5c0.3-1.2-0.2-1.9-1.6-2c-1.1-0.1-2.1-0.1-3.2,0c-1,0.1-1.9,0.4-3.1,0.8c-0.4-0.7-1.5-0.9-2.7-0.2c-0.2,0-0.6,0.1-0.7,0c-1.5-1-3.1-0.4-4.7-0.6c-1.1-0.1-2.2-0.1-2.9,1.3c-0.9-1.2-1.9-1.5-3.1-0.8c-0.2,0.2-0.6,0.1-0.9,0c-2.6-0.7-5.1-1-7.6,0.7c-0.7-1.1-1.7-1.2-2.8-0.6c-0.2,0.1-0.6,0.2-0.7,0.1c-1.5-1.1-3.2-0.6-4.8-0.7c-1.2-0.1-2.3,0-2.8,1.5c-1-0.5-2.9-0.4-3.9,0.2c0.2-1-0.4-1.6-1.6-1.7c-1.1-0.1-2.1-0.1-3.2,0c-1,0.1-1.9,0.4-3.1,0.8c-0.4-0.7-1.5-0.9-2.7-0.2c-0.2,0-0.6,0.1-0.7,0c-1.5-1-3.1-0.4-4.7-0.6c-1.1-0.1-2.2-0.1-2.9,1.3c-0.9-1.2-1.9-1.5-3.1-0.8c-0.2,0.2-0.6,0.1-0.9,0c-2.6-0.7-5.1-1-7.6,0.7c-0.7-1.1-1.7-1.2-2.8-0.6c-0.2,0.1-0.6,0.2-0.7,0.1c-1.5-1.1-3.2-0.6-4.8-0.7c-1.2-0.1-2.3,0-2.8,1.5c-1.3-0.7-4-0.3-4.5,0.8C-4,25.5-4.8,27.3-4.2,29c2.6,1.2,4.1,3.5,6.1,5.3c-3.2,1.2-4.1-1.8-6-2.8c-0.7,1.5,1,1.9,1.3,3c-1.7-0.1-1.6,0.9-1.6,1.9C-4.2,37.7-3.2,37.4-2.5,37.4z M7.8,33.9c-1.2-1.3-2.7-2.6-4.2-4c1.7-0.3,2.9-0.3,3.9,0.8c1.1,1.3,2.6,2.6,4,4C9.8,34.9,8.7,34.9,7.8,33.9z M16.6,33.6c-1.1-1.2-2.5-2.3-3.9-3.7c1.7-0.4,2.8-0.4,3.8,0.6c1.3,1.3,2.8,2.6,4.5,4.1C18.9,35,17.7,34.8,16.6,33.6z M21.2,33.6c-1.2-1.2-2.6-2.3-4-3.7c1.8-0.4,2.9-0.4,4,0.7c1.3,1.3,2.7,2.6,4.4,4C23.5,35,22.3,34.8,21.2,33.6z M35.1,33.7c-1.1-1.2-2.5-2.3-4-3.8c1.6-0.3,2.7-0.6,3.7,0.4c1.5,1.3,2.9,2.7,4.6,4.2C37.5,35,36.4,34.9,35.1,33.7z M41,34.5c-1.7-1.6-3.4-3.1-5.1-4.8c1.9-0.3,3.1-0.1,4.1,1.1c0.4,0.5,0.8,0.9,1.3,1.4c0.1,0.9,1.2,1.4,1.5,2.3c-0.4,0-0.7,0-0.9,0.1c-0.1,0-0.2,0-0.3,0C41.3,34.6,41.1,34.6,41,34.5z M42.9,32.7c0-0.1,0-0.2,0-0.2c-0.6-0.8-1.3-1.7-2-2.6c0.2-0.1,0.3-0.2,0.2-0.7c0.2,0,0.3-0.1,0.4-0.1c2.4,1.2,4,3.4,5.9,5.1C45.1,35.1,44,33.8,42.9,32.7z M53.3,33.9c-1.2-1.3-2.7-2.6-4.2-4c1.7-0.3,2.9-0.3,3.9,0.8c1.1,1.3,2.6,2.6,4,4C55.3,34.9,54.2,34.9,53.3,33.9z M62.1,33.6c-1.1-1.2-2.5-2.3-3.9-3.7c1.7-0.4,2.8-0.4,3.8,0.6c1.3,1.3,2.8,2.6,4.5,4.1C64.4,35,63.2,34.8,62.1,33.6z M66.7,33.6c-1.2-1.2-2.6-2.3-4-3.7c1.8-0.4,2.9-0.4,4,0.7c1.3,1.3,2.7,2.6,4.4,4C69,35,67.8,34.8,66.7,33.6z M84.9,34.6c-1.9,0.4-3,0.3-4.2-0.9c-1.1-1.2-2.5-2.3-4-3.8c1.6-0.3,2.7-0.6,3.7,0.4C81.8,31.7,83.2,33,84.9,34.6z M83,23.1c1.5,0,2.8,0,4.6,0c-0.3,1.2-0.4,2.2-1.1,2.9c-0.4,0.4-1.7,0.9-2.2,0.7c-1.1-0.3-2.1-1.3-2-2.7C82.3,23.6,82.8,23.1,83,23.1z M78.4,23.4c1.2-0.3,1.6,0.6,2.1,1.1c0.4,0.4,0.6,1.2,0.8,1.9c0,0.1-0.6,0.4-0.8,0.4c-1.3,0-2.7,0-4.2,0C76.7,25.4,76.7,24,78.4,23.4z M80.3,34.6c-1.7,0.3-2.8,0.4-3.9-0.7c-1.3-1.2-2.8-2.5-4.1-3.7c0.1-0.1,0.2-0.3,0.3-0.4c1.3-0.3,2.5-0.2,3.5,0.9C77.3,32,78.7,33.1,80.3,34.6z M70.9,23.7c0.1-0.3,0.6-0.6,0.9-0.7c0.6-0.1,1.1,0,1.7,0c0.1,0,0.2-0.1,0.4,0c0.7,0.2,2-0.7,2,0.8c0,1.9-1.1,3.1-2.6,3C72.1,26.9,70.6,24.9,70.9,23.7z M75.2,34.7c-1.3,0.2-2.6,0.2-3.6-0.9c-1.2-1.3-2.7-2.6-4.1-3.9C70,29.3,73.3,31.4,75.2,34.7z M67.6,23.3c1,0.1,2.3,2.1,2.2,3.5c-1.5,0-3.1,0-4.7,0C65.1,24.6,66.1,23.2,67.6,23.3z M59.6,23.5c0.1-0.2,0.4-0.6,0.8-0.6c1.1,0,2.2,0,3.4,0c0.8,0,0.9,0.4,0.8,1.1c-0.4,2-1,2.8-2.3,2.8C60.9,26.9,59.1,24.9,59.6,23.5z M56.4,23.3c1,0.1,2.3,2.2,2.1,3.5c-1.6,0-3.1,0-4.7,0C53.9,24.5,54.9,23.1,56.4,23.3z M57.4,30.6c1.3,1.3,2.7,2.6,4.4,4c-1.8,0.3-2.9,0.4-3.9-0.7c-1.2-1.3-2.7-2.6-4-3.8C55.3,29.5,56.4,29.5,57.4,30.6z M48.2,23.6c0-0.2,0.4-0.6,0.8-0.6c0.6,0,1.1,0,1.7,0c0.1,0,0.3-0.1,0.4,0c0.8,0.2,1.9-0.6,2.1,0.7c0.2,1.5-1,3-2.2,3.1C49.6,27,47.8,25,48.2,23.6z M51.4,33.8c0.2,0.2,0.4,0.6,0.8,0.9c-1.7,0.4-2.9,0-4-1.1c-1.1-1.2-2.5-2.2-3.6-3.5c1.5-0.6,2.6-0.7,3.6,0.4C49.1,31.7,50.2,32.7,51.4,33.8z M45,24c0.8,0,2.2,1.6,2.5,2.8c-1.6,0-3,0-4.6,0C43,25,43.6,24.1,45,24z M37.5,23.1c1.5,0,2.8,0,4.6,0c-0.3,1.2-0.4,2.2-1.1,2.9c-0.4,0.4-1.7,0.9-2.2,0.7c-1.1-0.3-2.1-1.3-2-2.7C36.8,23.6,37.3,23.1,37.5,23.1z M32.9,23.4c1.2-0.3,1.6,0.6,2.1,1.1c0.4,0.4,0.6,1.2,0.8,1.9c0,0.1-0.6,0.4-0.8,0.4c-1.3,0-2.7,0-4.2,0C31.2,25.4,31.2,24,32.9,23.4z M34.8,34.6c-1.7,0.3-2.8,0.4-3.9-0.7c-1.3-1.2-2.8-2.5-4.1-3.7c0.1-0.1,0.2-0.3,0.3-0.4c1.3-0.3,2.5-0.2,3.5,0.9C31.8,32,33.2,33.1,34.8,34.6z M25.4,23.7c0.1-0.3,0.6-0.6,0.9-0.7c0.6-0.1,1.1,0,1.7,0c0.1,0,0.2-0.1,0.4,0c0.7,0.2,2-0.7,2,0.8c0,1.9-1.1,3.1-2.6,3C26.6,26.9,25.1,24.9,25.4,23.7z M29.7,34.7c-1.3,0.2-2.6,0.2-3.6-0.9c-1.2-1.3-2.7-2.6-4.1-3.9C24.5,29.3,27.8,31.4,29.7,34.7z M22.1,23.3c1,0.1,2.3,2.1,2.2,3.5c-1.5,0-3.1,0-4.7,0C19.6,24.6,20.6,23.2,22.1,23.3z M14.1,23.5c0.1-0.2,0.4-0.6,0.8-0.6c1.1,0,2.2,0,3.4,0c0.8,0,0.9,0.4,0.8,1.1c-0.4,2-1,2.8-2.3,2.8C15.4,26.9,13.6,24.9,14.1,23.5z M10.9,23.3c1,0.1,2.3,2.2,2.1,3.5c-1.6,0-3.1,0-4.7,0C8.4,24.5,9.4,23.1,10.9,23.3z M11.9,30.6c1.3,1.3,2.7,2.6,4.4,4c-1.8,0.3-2.9,0.4-3.9-0.7c-1.2-1.3-2.7-2.6-4-3.8C9.8,29.5,10.9,29.5,11.9,30.6z M2.7,23.6c0-0.2,0.4-0.6,0.8-0.6c0.6,0,1.1,0,1.7,0c0.1,0,0.3-0.1,0.4,0c0.8,0.2,1.9-0.6,2.1,0.7c0.2,1.5-1,3-2.2,3.1C4.1,27,2.3,25,2.7,23.6z M-0.5,24c0.8,0,2.2,1.6,2.5,2.8c-1.6,0-3,0-4.6,0C-2.5,25-1.9,24.1-0.5,24z M-1,30.1c1.5-0.6,2.6-0.7,3.6,0.4c1,1.1,2.1,2.1,3.2,3.2c0.2,0.2,0.4,0.6,0.8,0.9c-1.7,0.4-2.9,0-4-1.1C1.5,32.3,0.2,31.3-1,30.1z"/><path d="M36.4,47c-1.3-0.1-2.6,1-2.6,2.5c0,1.3,0.9,2.5,2.3,2.5c1.5,0.1,2.6-0.9,2.6-2.3C38.7,48.2,37.7,47.1,36.4,47z"/><path d="M30.9,50.8c-1.1,0-2,0.9-1.9,2.1c0,1.1,0.9,1.9,2,1.9c1.1-0.1,2.1-1.1,2-2.1C32.9,51.6,32,50.8,30.9,50.8z"/><path d="M23.2,46.9c-0.9-0.1-1.6,0.6-1.6,1.5c0,0.9,0.6,1.5,1.5,1.5c0.9,0,1.5-0.4,1.5-1.5C24.6,47.5,24.1,47,23.2,46.9z"/><path d="M15.2,47c-1.3-0.1-2.6,1-2.6,2.5c0,1.3,0.9,2.5,2.3,2.5c1.5,0.1,2.6-0.9,2.6-2.3C17.5,48.2,16.5,47.1,15.2,47z"/><path d="M6.4,50.8c-1.1,0-2,0.9-1.9,2.1c0,1.1,0.9,1.9,2,1.9c1.1-0.1,2.1-1.1,2-2.1C8.4,51.6,7.5,50.8,6.4,50.8z"/><path d="M0.7,46.9c-0.9-0.1-1.6,0.6-1.6,1.5c0,0.9,0.6,1.5,1.5,1.5c0.9,0,1.5-0.4,1.5-1.5C2,47.5,1.5,47,0.7,46.9z"/><path d="M86.8,40.2c-14.5,0-29.2,0-43.8,0c-0.3,0-0.7-0.1-0.9,0c0,0-0.1,0-0.1,0c-0.2,0-0.4,0-0.7,0c-14.5,0-29.2,0-43.8,0c-0.3,0-0.7-0.1-0.9,0c-0.2,0.1-0.6,0.3-0.7,0.6c-0.6,1.5,0,2.2,1.6,2.1c1.5-0.1,2.5,0.2,3,1.6c0.1,0.1,0.3,0.3,0.6,0.6c0.3-0.6,0.6-1,0.9-1.3c0.4-0.3,0.9-0.8,1.5-0.8c0.3,0,0.8,0.6,1,0.9C4.9,44.3,5.1,45,5.5,46c0.6-2.5,1.7-3.7,4.1-3.4c1.9,0.3,4.1-0.6,4.8,2.3c0.6-2,1.7-2.3,3.5-2.2c1.6,0.1,3.2,0.1,4.9,0c0.9,0,1.5,0.3,1.7,1.1c0.2,1,0.7,1.9,1.2,3.2c0.6-1.3,1-2.3,1.3-3.2c0.2-0.9,0.8-1.1,1.7-1.1c1.8,0.1,3.5,0.1,5.1,0c1.9-0.1,3.2,0.2,3.8,2.2c0.1,0.1,0.2,0.1,0.4,0.2c0.3-2.1,1.9-2.6,3.9-2.3c0,0,0.1,0,0.1,0c0.2,0,0.5,0.1,0.8,0c1.5-0.1,2.5,0.2,3,1.6c0.1,0.1,0.3,0.3,0.6,0.6c0.3-0.6,0.6-1,0.9-1.3c0.4-0.3,0.9-0.8,1.5-0.8c0.3,0,0.8,0.6,1,0.9c0.4,0.6,0.7,1.2,1.1,2.2c0.6-2.5,1.7-3.7,4.1-3.4c1.9,0.3,4.1-0.6,4.8,2.3c0.6-2,1.7-2.3,3.5-2.2c1.6,0.1,3.2,0.1,4.9,0c0.9,0,1.5,0.3,1.7,1.1c0.2,1,0.7,1.9,1.2,3.2c0.6-1.3,1-2.3,1.3-3.2c0.2-0.9,0.8-1.1,1.7-1.1c1.8,0.1,3.5,0.1,5.1,0c1.9-0.1,3.2,0.2,3.8,2.2c0.1,0.1,0.2,0.1,0.4,0.2c0.3-2.1,1.9-2.6,3.9-2.3c0.2,0,0.7-0.4,0.8-0.8C88.7,40.5,88.3,40.2,86.8,40.2z"/><path d="M81.9,47c-1.3-0.1-2.6,1-2.6,2.5c0,1.3,0.9,2.5,2.3,2.5c1.5,0.1,2.6-0.9,2.6-2.3C84.2,48.2,83.2,47.1,81.9,47z"/><path d="M76.4,50.8c-1.1,0-2,0.9-1.9,2.1c0,1.1,0.9,1.9,2,1.9c1.1-0.1,2.1-1.1,2-2.1C78.4,51.6,77.5,50.8,76.4,50.8z"/><path d="M68.7,46.9c-0.9-0.1-1.6,0.6-1.6,1.5c0,0.9,0.6,1.5,1.5,1.5c0.9,0,1.5-0.4,1.5-1.5C70.1,47.5,69.6,47,68.7,46.9z"/><path d="M60.7,47c-1.3-0.1-2.6,1-2.6,2.5c0,1.3,0.9,2.5,2.3,2.5C61.9,52,63,51,63,49.6C63,48.2,62,47.1,60.7,47z"/><path d="M51.9,50.8c-1.1,0-2,0.9-1.9,2.1c0,1.1,0.9,1.9,2,1.9c1.1-0.1,2.1-1.1,2-2.1C53.9,51.6,53,50.8,51.9,50.8z"/><path d="M46.2,46.9c-0.9-0.1-1.6,0.6-1.6,1.5c0,0.9,0.6,1.5,1.5,1.5s1.5-0.4,1.5-1.5C47.5,47.5,47,47,46.2,46.9z"/></g></g><g><g><polyline class="image-set-annotation-labels-geology-st1" points="80.7,64.7 80.7,65.7 79.7,65.7 "/><line class="image-set-annotation-labels-geology-st2" x1="77.7" y1="65.7" x2="6.3" y2="65.7"/><polyline class="image-set-annotation-labels-geology-st1" points="5.3,65.7 4.3,65.7 4.3,64.7 "/><line class="image-set-annotation-labels-geology-st3" x1="4.3" y1="62.7" x2="4.3" y2="12.5"/><polyline class="image-set-annotation-labels-geology-st1" points="4.3,11.5 4.3,10.5 5.3,10.5 "/><line class="image-set-annotation-labels-geology-st2" x1="7.3" y1="10.5" x2="78.7" y2="10.5"/><polyline class="image-set-annotation-labels-geology-st1" points="79.7,10.5 80.7,10.5 80.7,11.5 "/><line class="image-set-annotation-labels-geology-st3" x1="80.7" y1="13.5" x2="80.7" y2="63.7"/></g></g><g><path d="M72.1,84.7c-0.1,0-0.2,0-0.4-0.1c-0.2-0.1-0.4-0.3-0.6-0.5l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.2,0.5,0,1.1-0.5,1.3l-2.8,1.2C72.4,84.7,72.3,84.7,72.1,84.7z"/><path class="image-set-annotation-labels-geology-st4" d="M63.6,61l12.6,13.3L71.1,74l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L63.6,61 M63.6,59c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2l1.6,18.2c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L65,59.6C64.6,59.2,64.1,59,63.6,59L63.6,59z"/></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-annotation-labels_operation.svg b/docs/ifdos/svgs/image-annotation-labels_operation.svg deleted file mode 100644 index 9c4e064c2c33d7fb52ea14544a7c631d74e3d9d2..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-annotation-labels_operation.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-annotation-labels_operation" alt="image-set-annotation-labels is operation" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-annotation-labels is operation</title><style type="text/css">.image-set-annotation-labels-operation-st0{fill:none;stroke:#000000;stroke-miterlimit:10;}.image-set-annotation-labels-operation-st1{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:2.0119,2.0119;}.image-set-annotation-labels-operation-st2{fill:none;stroke:#000000;stroke-miterlimit:10;stroke-dasharray:1.9682,1.9682;}.image-set-annotation-labels-operation-st3{fill:#FFFFFF;}.image-set-annotation-labels-operation-st4{fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}</style><g><g><polyline class="image-set-annotation-labels-operation-st0" points="80.7,64.7 80.7,65.7 79.7,65.7 "/><line class="image-set-annotation-labels-operation-st1" x1="77.7" y1="65.7" x2="6.3" y2="65.7"/><polyline class="image-set-annotation-labels-operation-st0" points="5.3,65.7 4.3,65.7 4.3,64.7 "/><line class="image-set-annotation-labels-operation-st2" x1="4.3" y1="62.7" x2="4.3" y2="12.5"/><polyline class="image-set-annotation-labels-operation-st0" points="4.3,11.5 4.3,10.5 5.3,10.5 "/><line class="image-set-annotation-labels-operation-st1" x1="7.3" y1="10.5" x2="78.7" y2="10.5"/><polyline class="image-set-annotation-labels-operation-st0" points="79.7,10.5 80.7,10.5 80.7,11.5 "/><line class="image-set-annotation-labels-operation-st2" x1="80.7" y1="13.5" x2="80.7" y2="63.7"/></g></g><g><path d="M72.1,84.7c-0.1,0-0.2,0-0.4-0.1c-0.2-0.1-0.4-0.3-0.6-0.5l-3.1-6.9l-2.2,2.7c-0.2,0.2-0.5,0.4-0.8,0.4c-0.1,0-0.2,0-0.3,0c-0.4-0.1-0.7-0.5-0.7-0.9l-1.6-18.2c0-0.4,0.2-0.8,0.6-1c0.1-0.1,0.3-0.1,0.4-0.1c0.3,0,0.5,0.1,0.7,0.3l12.6,13.3c0.3,0.3,0.4,0.7,0.2,1.1c-0.2,0.4-0.5,0.6-0.9,0.6c0,0-3.5-0.1-3.5-0.1l3.1,6.9c0.2,0.5,0,1.1-0.5,1.3l-2.8,1.2C72.4,84.7,72.3,84.7,72.1,84.7z"/><path class="image-set-annotation-labels-operation-st3" d="M63.6,61l12.6,13.3L71.1,74l3.8,8.4l-2.8,1.3l-3.8-8.4l-3.2,3.9L63.6,61 M63.6,59c-0.3,0-0.6,0.1-0.8,0.2c-0.8,0.3-1.2,1.2-1.2,2l1.6,18.2c0.1,0.8,0.6,1.5,1.4,1.7c0.2,0.1,0.4,0.1,0.6,0.1c0.6,0,1.2-0.3,1.6-0.7l1.2-1.4l2.5,5.5c0.3,0.7,1.1,1.2,1.8,1.2c0.3,0,0.6-0.1,0.8-0.2l2.8-1.3c0.5-0.2,0.9-0.6,1-1.1c0.2-0.5,0.2-1,0-1.5l-2.5-5.5l1.8,0.1c0,0,0.1,0,0.1,0c0.8,0,1.5-0.5,1.8-1.2c0.3-0.7,0.2-1.6-0.4-2.2L65,59.6C64.6,59.2,64.1,59,63.6,59L63.6,59z"/></g><g><rect x="16.6" y="32.5" width="47.7" height="8.3"/><polyline class="image-set-annotation-labels-operation-st4" points="67.8,50.4 64.3,50.4 62.8,52.2 56.2,52.2 "/><polyline class="image-set-annotation-labels-operation-st4" points="67.8,54.1 64.3,54.1 62.8,52.2 "/><path d="M16.6,42.2v17.2h36.8l4.4-11.8l6.5-5.4H16.6z M25.8,56.5c-2.9,0-5.2-2.3-5.2-5.2s2.3-5.2,5.2-5.2s5.2,2.3,5.2,5.2S28.7,56.5,25.8,56.5z"/><path class="image-set-annotation-labels-operation-st4" d="M39,33.9c0,0-2-2-1.8-4.8c0.2-3,1-3.1,0.8-4.9c-0.2-2.7-4.5-5.9-8.6-7.4"/><path d="M28.8,50.4h-2.7l-1.2-2.2c-0.2-0.4-0.8-0.6-1.2-0.4c-0.4,0.2-0.6,0.8-0.4,1.2l1.2,2.2l-1.2,2.3c-0.2,0.4-0.1,1,0.4,1.2c0.1,0.1,0.3,0.1,0.4,0.1c0.3,0,0.6-0.2,0.8-0.5l1.2-2.3h2.7c0.5,0,0.9-0.4,0.9-0.9C29.7,50.8,29.3,50.4,28.8,50.4z"/></g></svg> \ No newline at end of file diff --git a/docs/ifdos/svgs/image-navigation_sattelite.svg b/docs/ifdos/svgs/image-navigation_sattelite.svg deleted file mode 100644 index b4fb4a8bc561884d40a46f239ac5a8ae7b57f82f..0000000000000000000000000000000000000000 --- a/docs/ifdos/svgs/image-navigation_sattelite.svg +++ /dev/null @@ -1 +0,0 @@ -<svg version="1.1" id="image-set-navigation_sattelite" alt="image-set-navigation is sattelite" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 85 85" style="enable-background:new 0 0 85 85;" xml:space="preserve"><title>image-set-navigation is sattelite</title><style type="text/css">.image-set-navigation-sattelite-st0{fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}.image-set-navigation-sattelite-st1{fill:#FFFFFF;}.image-set-navigation-sattelite-st2{fill:#FFFFFF;stroke:#000000;stroke-width:2;stroke-miterlimit:10;}.image-set-navigation-sattelite-st3{clip-path:url(#SGVIDimage-set-navigationsattelite_2_);}.image-set-navigation-sattelite-st4{clip-path:url(#SGVIDimage-set-navigationsattelite_4_);}.image-set-navigation-sattelite-st5{clip-path:url(#SGVIDimage-set-navigationsattelite_6_);}.image-set-navigation-sattelite-st6{clip-path:url(#SGVIDimage-set-navigationsattelite_8_);}.image-set-navigation-sattelite-st7{fill:#FFFFFF;stroke:#FFFFFF;stroke-linejoin:round;stroke-miterlimit:10;}</style><path class="image-set-navigation-sattelite-st0" d="M4.3,62.1c4.3,0,4.3,3.7,8.5,3.7c4.3,0,4.3-3.7,8.5-3.7c4.3,0,4.3,3.7,8.5,3.7c4.3,0,4.3-3.7,8.5-3.7c4.3,0,4.3,3.7,8.5,3.7c4.3,0,4.3-3.7,8.5-3.7c4.3,0,4.3,3.7,8.5,3.7c4.3,0,4.3-3.7,8.5-3.7s4.3,3.7,8.5,3.7"/><path d="M44.3,10.8l9.5,9.5c0.1-0.3,0.3-0.5,0.5-0.8s0.5-0.6,0.7-0.9c0.9-0.9,2-1.5,3.2-1.7c0.5-0.1,1-0.2,1.5-0.2l1.3-1.3c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3L50.7,4.5c-0.1-0.1-0.2-0.1-0.3-0.1s-0.2,0-0.3,0.1l-5.7,5.7c-0.1,0.1-0.1,0.2-0.1,0.3C44.2,10.6,44.2,10.7,44.3,10.8z"/><path d="M68.2,23.3c1.6-1.8,1.5-4.5-0.2-6.2s-4.4-1.8-6.2-0.2c1.5,0.4,2.9,1.1,4.1,2.3C67.1,20.4,67.8,21.8,68.2,23.3z"/><path d="M57.2,29c0,0.1,0.1,0.1,0.1,0.2v0.2c0,0.2,0.1,0.4,0.1,0.6c2.8,1.9,6.4,1.8,8.6-0.4c2.5-2.5,2.3-7-0.6-9.8c-2.9-2.9-7.3-3.2-9.8-0.6c-2.3,2.3-2.3,6-0.2,8.8h0.1c0.1,0,0.3,0,0.4,0c0.1,0,0.1,0,0.2,0.1c0.1,0,0.2,0.1,0.2,0.1l4.1-4.1c0.2-0.2,0.7-0.2,0.9,0s0.2,0.7,0,0.9L57.2,29z"/><path d="M55.4,32.2c-0.6,0-1.2-0.2-1.7-0.7c-0.4-0.4-0.7-1-0.7-1.7c0-0.6,0.2-1.2,0.7-1.7c0.4-0.4,0.9-0.6,1.5-0.7c0.1,0,0.1,0,0.1,0c0.2,0,0.3,0,0.5,0.1c0.1,0,0.2,0,0.3,0.1l0,0l3.9-3.9c0.2-0.2,0.4-0.3,0.7-0.3s0.5,0.1,0.7,0.3c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7L57.5,29l0.1,0.2c0.1,0.2,0.1,0.4,0.1,0.7c0,0.6-0.3,1.2-0.7,1.6C56.6,32,56,32.2,55.4,32.2z"/><path class="image-set-navigation-sattelite-st1" d="M60.8,23.8c0.2,0,0.3,0.1,0.4,0.2c0.2,0.2,0.2,0.7,0,0.9L57.1,29c0,0.1,0.1,0.1,0.1,0.2v0.2c0,0.2,0.1,0.4,0.1,0.6c0,0.5-0.2,1-0.6,1.3c-0.4,0.4-0.9,0.6-1.4,0.6s-1-0.2-1.4-0.6s-0.6-0.9-0.6-1.4s0.2-1,0.6-1.4c0.3-0.3,0.8-0.5,1.3-0.6h0.1c0.1,0,0.3,0,0.4,0c0.1,0,0.1,0,0.2,0.1c0.1,0,0.2,0.1,0.2,0.1l4.1-4.1C60.5,23.9,60.7,23.8,60.8,23.8 M60.8,23c-0.4,0-0.7,0.1-1,0.4L56,27.2h-0.1c-0.2,0-0.4-0.1-0.6-0.1c-0.1,0-0.1,0-0.2,0c-0.7,0-1.3,0.3-1.8,0.8s-0.8,1.2-0.8,1.9c0,0.7,0.3,1.4,0.8,1.9s1.2,0.8,1.9,0.8s1.4-0.3,1.9-0.8s0.8-1.1,0.8-1.8c0-0.3,0-0.5-0.1-0.8l0,0l3.8-3.8c0.3-0.3,0.4-0.6,0.4-1s-0.1-0.7-0.4-1C61.6,23.2,61.2,23,60.8,23L60.8,23z"/><path d="M74.6,40.9c0.1,0,0.2,0,0.3-0.1l5.7-5.7c0.1-0.1,0.1-0.2,0.1-0.3c0-0.1,0-0.2-0.1-0.3L70.3,24.2c-0.1-0.1-0.2-0.1-0.3-0.1s-0.2,0-0.3,0.1l-1.3,1.3c0,0.5-0.1,1-0.2,1.5c-0.3,1.2-0.9,2.3-1.7,3.2c-0.3,0.3-0.6,0.5-0.9,0.7c-0.3,0.2-0.5,0.3-0.8,0.5l9.5,9.5C74.4,40.8,74.5,40.9,74.6,40.9z"/><ellipse class="image-set-navigation-sattelite-st2" cx="20.6" cy="61" rx="9.4" ry="2.9"/><path d="M20.7,61.8c-0.2,0-0.3-0.1-0.4-0.2l-5.5-8.8c-1.7-2.6-2.6-4-2.6-6.5c0-4.7,3.8-8.5,8.5-8.5c0.1,0,0.3,0,0.4,0c0.1,0,0.2,0,0.3,0c4.3,0.4,7.7,4.1,7.7,8.4c0,2.6-1.1,4.3-2.5,6.5l-4.8,7.7l-0.7,1.2C21.1,61.7,20.9,61.8,20.7,61.8L20.7,61.8z M20.7,42.4c-2.1,0-3.8,1.7-3.8,3.8c0,2.1,1.7,3.8,3.8,3.8s3.8-1.7,3.8-3.8C24.6,44.1,22.9,42.4,20.7,42.4z"/><path class="image-set-navigation-sattelite-st1" d="M20.7,38.3c0.1,0,0.3,0,0.4,0c0.1,0,0.2,0,0.3,0c4.1,0.4,7.3,3.8,7.3,7.9c0,2.4-1,4-2.4,6.2l-4.8,7.7l-0.7,1.2l-0.7-1.1l-4.8-7.7c-1.7-2.6-2.5-3.9-2.5-6.2C12.8,41.9,16.3,38.3,20.7,38.3 M20.7,50.5c2.4,0,4.3-1.9,4.3-4.3s-1.9-4.3-4.3-4.3c-2.4,0-4.3,1.9-4.3,4.3C16.4,48.6,18.3,50.5,20.7,50.5 M20.7,37.3c-5,0-9,4-9,9c0,2.7,0.9,4.1,2.7,6.8l4.8,7.7l0.7,1.1c0.2,0.3,0.5,0.5,0.8,0.5l0,0c0.3,0,0.7-0.2,0.8-0.5l0.7-1.2L27,53c1.4-2.1,2.6-4,2.6-6.7c0-4.6-3.6-8.5-8.2-8.9c-0.1,0-0.2,0-0.3,0C21.1,37.3,20.9,37.3,20.7,37.3L20.7,37.3z M20.7,49.5c-1.8,0-3.3-1.5-3.3-3.3s1.5-3.3,3.3-3.3s3.3,1.5,3.3,3.3C24.1,48,22.6,49.5,20.7,49.5L20.7,49.5z"/><g><defs><path id="SGVIDimage-set-navigationsattelite_1_" d="M56,29.6H35.2c0,11.5,9.3,20.8,20.8,20.8V29.6z"/></defs><clipPath id="SGVIDimage-set-navigationsattelite_2_"><use xlink:href="#SGVIDimage-set-navigationsattelite_1_" style="overflow:visible;"/></clipPath><path class="image-set-navigation-sattelite-st3" d="M56,38.6c-5,0-9-4-9-9s4-9,9-9s9,4,9,9S61,38.6,56,38.6z M56,22.5c-3.9,0-7.1,3.2-7.1,7.1s3.2,7.1,7.1,7.1c3.9,0,7.1-3.2,7.1-7.1S59.9,22.5,56,22.5z"/></g><g><defs><path id="SGVIDimage-set-navigationsattelite_3_" d="M56,29.6H35.2c0,11.5,9.3,20.8,20.8,20.8V29.6z"/></defs><clipPath id="SGVIDimage-set-navigationsattelite_4_"><use xlink:href="#SGVIDimage-set-navigationsattelite_3_" style="overflow:visible;"/></clipPath><path class="image-set-navigation-sattelite-st4" d="M56,42.4c-7.1,0-12.8-5.8-12.8-12.8S49,16.8,56,16.8c7.1,0,12.8,5.8,12.8,12.8S63.1,42.4,56,42.4z M56,18.7c-6,0-10.9,4.9-10.9,10.9S50,40.5,56,40.5s10.9-4.9,10.9-10.9S62.1,18.7,56,18.7z"/></g><g><defs><path id="SGVIDimage-set-navigationsattelite_5_" d="M56,29.6H35.2c0,11.5,9.3,20.8,20.8,20.8V29.6z"/></defs><clipPath id="SGVIDimage-set-navigationsattelite_6_"><use xlink:href="#SGVIDimage-set-navigationsattelite_5_" style="overflow:visible;"/></clipPath><path class="image-set-navigation-sattelite-st5" d="M56,46.4c-9.2,0-16.8-7.5-16.8-16.8S46.7,12.8,56,12.8s16.8,7.5,16.8,16.8S65.3,46.4,56,46.4z M56,14.8c-8.2,0-14.8,6.7-14.8,14.8S47.9,44.4,56,44.4c8.2,0,14.8-6.7,14.8-14.8S64.2,14.8,56,14.8z"/></g><g><defs><path id="SGVIDimage-set-navigationsattelite_7_" d="M56,29.6H35.2c0,11.5,9.3,20.8,20.8,20.8V29.6z"/></defs><clipPath id="SGVIDimage-set-navigationsattelite_8_"><use xlink:href="#SGVIDimage-set-navigationsattelite_7_" style="overflow:visible;"/></clipPath><path class="image-set-navigation-sattelite-st6" d="M56,50.1c-11.3,0-20.5-9.2-20.5-20.5S44.7,9.1,56,9.1s20.5,9.2,20.5,20.5C76.6,40.9,67.4,50.1,56,50.1z M56,11c-10.3,0-18.6,8.4-18.6,18.6c0,10.3,8.4,18.6,18.6,18.6c10.3,0,18.6-8.4,18.6-18.6C74.7,19.3,66.3,11,56,11z"/></g><ellipse class="image-set-navigation-sattelite-st1" cx="20.6" cy="61" rx="9.4" ry="2.9"/><path d="M20.6,65.4C15.2,65.4,9.7,64,9.7,61s5.5-4.4,10.9-4.4S31.5,58,31.5,61S26,65.4,20.6,65.4z M12.8,61c0.7,0.4,3.3,1.4,7.8,1.4s7-0.9,7.7-1.4c-0.8-0.5-3.3-1.4-7.7-1.4C16.1,59.6,13.6,60.5,12.8,61z"/><path class="image-set-navigation-sattelite-st1" d="M20.6,57.1c5,0,10.4,1.2,10.4,3.9c0,2.7-5.4,3.9-10.4,3.9S10.2,63.7,10.2,61C10.1,58.3,15.5,57.1,20.6,57.1 M20.6,62.9c5.4,0,8.2-1.4,8.4-1.9c-0.2-0.5-3-1.9-8.4-1.9c-5.5,0-8.3,1.4-8.4,1.9C12.3,61.5,15.1,62.9,20.6,62.9 M20.6,56.1c-5.3,0-11.4,1.3-11.4,4.9s6.2,4.9,11.4,4.9S32,64.6,32,61C32,57.3,25.8,56.1,20.6,56.1L20.6,56.1z M14.1,61c1.2-0.4,3.3-0.9,6.5-0.9s5.3,0.5,6.5,0.9c-1.2,0.4-3.3,0.9-6.5,0.9C17.3,61.9,15.2,61.4,14.1,61L14.1,61z"/><path class="image-set-navigation-sattelite-st7" d="M21.4,38.3c-0.1,0-0.2,0-0.3,0s-0.3,0-0.4,0c-4.4,0-8,3.6-8,8c0,2.4,0.8,3.6,2.5,6.2l4.8,7.7l0.7,1.1l0.7-1.2l4.8-7.7c1.4-2.2,2.4-3.8,2.4-6.2C28.7,42.1,25.5,38.7,21.4,38.3z"/><path d="M20.7,61.8c-0.2,0-0.3-0.1-0.4-0.2l-5.5-8.8c-1.7-2.6-2.6-4-2.6-6.5c0-4.7,3.8-8.5,8.5-8.5c0.1,0,0.3,0,0.4,0c0.1,0,0.2,0,0.3,0c4.3,0.4,7.7,4.1,7.7,8.4c0,2.6-1.1,4.3-2.5,6.5l-4.8,7.7l-0.7,1.2C21.1,61.7,20.9,61.8,20.7,61.8L20.7,61.8z M20.7,42.4c-2.1,0-3.8,1.7-3.8,3.8c0,2.1,1.7,3.8,3.8,3.8s3.8-1.7,3.8-3.8C24.6,44.1,22.9,42.4,20.7,42.4z"/><path class="image-set-navigation-sattelite-st1" d="M20.7,38.3c0.1,0,0.3,0,0.4,0c0.1,0,0.2,0,0.3,0c4.1,0.4,7.3,3.8,7.3,7.9c0,2.4-1,4-2.4,6.2l-4.8,7.7l-0.7,1.2l-0.7-1.1l-4.8-7.7c-1.7-2.6-2.5-3.9-2.5-6.2C12.8,41.9,16.3,38.3,20.7,38.3 M20.7,50.5c2.4,0,4.3-1.9,4.3-4.3s-1.9-4.3-4.3-4.3c-2.4,0-4.3,1.9-4.3,4.3C16.4,48.6,18.3,50.5,20.7,50.5 M20.7,37.3c-5,0-9,4-9,9c0,2.7,0.9,4.1,2.7,6.8l4.8,7.7l0.7,1.1c0.2,0.3,0.5,0.5,0.8,0.5l0,0c0.3,0,0.7-0.2,0.8-0.5l0.7-1.2L27,53c1.4-2.1,2.6-4,2.6-6.7c0-4.6-3.6-8.5-8.2-8.9c-0.1,0-0.2,0-0.3,0C21.1,37.3,20.9,37.3,20.7,37.3L20.7,37.3z M20.7,49.5c-1.8,0-3.3-1.5-3.3-3.3s1.5-3.3,3.3-3.3s3.3,1.5,3.3,3.3C24.1,48,22.6,49.5,20.7,49.5L20.7,49.5z"/></svg> \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 810778713c20ae6b09f85170af27d1ed0fc4790b..505be4ce3783955e2191fb7eecb9d2a04b5d7bbd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,4 +1,9 @@ -> **Preamble:** We strive to make marine image data [FAIR](FAIR-marine-images.md). We maintain [metadata profiles](ifdos/iFDO-overview.md) to establish a common language of marine imagery, we develop best-practice [operating procedures](sops/sop-overview.md) for handling marine images and we develop [software tools](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/) to apply the vocabulary and procedures to marine imagery. +> **Preamble:** We strive to make marine image data [FAIR](FAIR-marine-images.md). We maintain the iFDO [metadata +> vocabulary](overview/iFDO-overview.md) to establish a common language for describing marine imagery, we provide +> [metadata schemas](https://codebase.helmholtz.cloud/datahub/marehub/ag-videosimages/fair-marine-images/-/tree/v2.0.0/resources/schemas/ifdo-v2.0.0.json) to link the iFDO format to established metadata standards, +> we develop +> best-practice [standard operating procedures](sops/sop-overview.md) for handling marine images, and we +> implement [software tools](https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/) to apply the vocabulary and procedures to marine imagery. ## FAIRness The buzzterm [FAIR](https://www.go-fair.org/fair-principles/) is an acronym for Findable, Accessible, Interoperable and Reusable. Which you probably knew already. Sorry. But in case you didn't: its the big idea, currently driving research data management (RDM) and a massive challenge for RDM infrastructure providers, maintainers and users. But it is also a fantastic opportunity to open up research by making research efforts more prominent and results more reliable. It appears everywhere nowadays, most importantly in project calls and thus project proposals. So while there is also no way around it, embracing this new data culture will change the face of research for the better! @@ -9,13 +14,26 @@ Achieving FAIRness and Openness of (marine) image data requires structured and s ## And where are the images? That is entirely up to you! iFDOs only contain metadata - including information on where images can be found. Ideally image data is also openly accessible, but this is not mandatory. Your images will likely be stored in a media asset management system (MAMS) that is ideally web-accessible and where the persistent identifiers in an iFDO file link to. So its easy to share image metadata data with iFDOs (they are small enough to be emailed if needed) and you simultaneously share the image data without moving it physically. -## Journal publication -The principles and workflows - described on these pages here - in detail have been published as a peer-reviewed journal article in Nature Scientific Data: https://doi.org/10.1038/s41597-022-01491-3 +## How do I get started using iFDOs? +1. Read this documentation to [explore the metadata fields](overview/iFDO-overview.md) that are required or constrained +2. Install a software that understands the iFDO concept (e.g. mariqt) +3. Look at [example iFDO](standard/{latest_version}/examples/ifdo-image-example.json) files +4. Collect your own image metadata, maybe by using the provided [Excel sheets](resources/sheets/Overview-iFDO-metadata-collection.xlsx) -Please cite this article in your own works in case you use iFDOs for your data. +## Journal publication +The principles and workflows - described on these pages here - have been published in detail as a peer-reviewed journal +article in Nature Scientific Data: [https://doi.org/10.1038/s41597-022-01491-3](https://doi.org/10.1038/s41597-022-01491-3) Please cite this article in your own +works in case you use iFDOs for your data. ## Standard Operating Procedures (SOPs) More hands-on material on creating and using iFDOs is available in two OceanBestPractices Bundles. One on [iFDO Creation](http://hdl.handle.net/11329/1782) and one on [Image curation and publication](http://hdl.handle.net/11329/1781). ### Vocabulary terms - what are images? -We use the following wording - based on Dublin Core - throughout these pages: [images](http://purl.org/dc/dcmitype/Image) are both photos (still images) and videos (moving images) acquired by cameras, recording the optical spectrum of light. [Still images](http://purl.org/dc/dcmitype/StillImage)are static visual representations, while [moving images](http://purl.org/dc/dcmitype/MovingImage) are a series of visual representations imparting an impression of motion when shown in succession. An [image set](http://purl.org/dc/dcmitype/Collection) is a collection of at least one, but usually many, images. We further use <tags> as placeholders for specific information (like a variable). +We use the following wording - based on Dublin Core - throughout these pages: [images](http://purl.org/dc/dcmitype/Image) are both photos (still images) and videos (moving images) acquired by cameras, recording the optical spectrum of light. [Still images](http://purl.org/dc/dcmitype/StillImage) are static visual representations, while [moving images](http://purl.org/dc/dcmitype/MovingImage) are a series of visual representations imparting an impression of motion when shown in succession. An [image set](http://purl.org/dc/dcmitype/Collection) is a collection of at least one, but usually many, images. We further use <tags> as placeholders for specific information (like a variable). + +## Imprint +These pages provide information created by several authors. You can contact [Timm Schoening](https://orcid.org/0000-0002-0035-3282) for details. With major contributions from: + +<img src="https://codebase.helmholtz.cloud/uploads/-/system/group/avatar/8380/HMC_Logo_SocialMedia_drk.jpg" alt="HMC logo" width="150" height="auto"> +<img src="https://datahub.hcdc.hereon.de/static/images/logo.png" alt="DataHub logo" width="150" height="auto"> +<img src="https://marine-imaging.com/assets/figures/mi_logo_2021.png" alt="MIC logo" width="150" height="auto"> diff --git a/docs/overview/iFDO-capture.md b/docs/overview/iFDO-capture.md new file mode 100644 index 0000000000000000000000000000000000000000..99bdc1a06931026b2241dc6378d8df5c98aeb7bb --- /dev/null +++ b/docs/overview/iFDO-capture.md @@ -0,0 +1,26 @@ +# iFDO capture fields +The iFDO capture is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about +its file formats, parts and sections. All fields in this section are optional! + +## Motivation +Information on how image data was captured can be crucial to understand information extracted from the images. It is +thus highly recommended to enrich all iFDOs with capture information. The potential metadata in the iFDO capture +fields is expected to grow with time, as additional (marine) imaging domains make use of this concept. Anyhow, below +you find a pool of iFDO capture fields which are highly recommended to be added to your iFDO. Only with these fields +populated will your dataset shine in a marine data portal! By limiting some of these fields to restricted values only, +it is possible to classify and filter image data sets in data portals and to visualize data characteristics. See the +[iFDO capture icon overview](../standard/{latest_version}/iFDO-icons.md) for more details. + + +## File format +All iFDO capture fields shall be stored alongside the core metadata in your iFDO file! It does not take up a +specific section of the file, rather the values are intermixed into the ``image-set-header`` and ``image-set-items`` +section! + +## iFDO capture fields + + +```json-schema-gen +schema: ../standard/{latest_version}/schema/ifdo-capture.json +external_property_page: ../standard/{latest_version}/documentation/iFDO-capture.md/ +``` \ No newline at end of file diff --git a/docs/overview/iFDO-content.md b/docs/overview/iFDO-content.md new file mode 100644 index 0000000000000000000000000000000000000000..84ba61957dec052c554c124b0a7a33cf97e918c0 --- /dev/null +++ b/docs/overview/iFDO-content.md @@ -0,0 +1,21 @@ +# iFDO content fields +The iFDO content is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about its file formats, parts and sections. All fields in this section are optional! + +## Motivation +Image data is inherently unstructured and obtaining a glimpse of its content is hard to achieve for humans as well as machines. The iFDOs content fields are a mechanism to encode the content of image data by means of visual, textual or other data proxies (annotations, previews, descriptions, categorisations, etc.). These can take various forms as described below. Simple examples of visual proxies are thumbnails for images or the average intensity along a video. + +## File format +All iFDO content fields shall be stored alongside the core metadata in your iFDO file! It does not take up a specific section of the file, rather the values are intermixed into the image-set-header and image-set-items section! + +## Domain-specific iFDO content fields + +```json-schema-gen +schema: ../standard/{latest_version}/schema/ifdo-content.json +external_property_page: ../standard/{latest_version}/documentation/iFDO-content.md/ +``` + +## iFDO content fields for annotations +```json-schema-gen +schema: ../standard/{latest_version}/schema/annotation.json +external_property_page: ../standard/{latest_version}/documentation/iFDO-content.md/ +``` diff --git a/docs/overview/iFDO-core.md b/docs/overview/iFDO-core.md new file mode 100644 index 0000000000000000000000000000000000000000..3e8ed437bf7038f92aae1cf675a43f773d622dc4 --- /dev/null +++ b/docs/overview/iFDO-core.md @@ -0,0 +1,51 @@ +# iFDO core +The iFDO core is one section of the complete [iFDO file](iFDO-overview.md). See its description to learn about its +file formats, parts and sections. + +## Header information in the `image-set-header` part +The `image-set-header` values have to exist and cannot be superseded by values of the `image-set-items`. +Fields from the `image-set-items` part (below) may exist in the header as default values for the entire image set. + +```json-schema-gen +schema: ../standard/{latest_version}/schema/ifdo-core.json +property_filter: image-set-.* +external_property_page: ../standard/{latest_version}/documentation/iFDO-core.md/ +``` + +In JSON, the entire `image-set-header` part is one dictionary. + +## Image item information + +```json-schema-gen +schema: ../standard/{latest_version}/schema/ifdo-core.json +property_filter: image-(?!.*set).* +external_property_page: ../standard/{latest_version}/documentation/iFDO-core.md/ +``` + +In JSON, the `image-set-items` part is one dictionary. The keys in that dictionary are the filenames of the items in +the image set. Each item, indexed by the `image-filename`, is itself either a dictionary if the item is an image or a list of dictionaries if the item is a video. +For videos, the first entry of the list contains the default fields for the entire video. Subsequent entries allow to add time-dependent metadata. Do not repeat static metadata for each second of +a video to avoid repetition. Every subsequent entry contains specifications that supersede the default values for +one specific time point of the video. For photos (still images) the dictionary contains the fields +tabled above. + +## UUIDs and hashes +### UUID +Making data FAIR requires - amongst other things - that data is assigned a persistent identifier (PID). Many such +PID systems exist, and usually they are based on the handle system (like DOIs for example) and alpha-numerical IDs +that are globally unique. For images, we chose to use UUIDs (*Universally Unique Identifiers*), more precisely UUID +type 4: random. These UUIDs can be created by anyone and as there are ca 21^36 possible UUID4s making it almost +impossible that the same one is created more than once. This UUID is the alphanumerical identifier that has to be +assigned to each image and to each image set. That means that the UUID for an image item (a photo or video) *has to +become part of the file itself!* You need to write it into the image file's metadata header. How this can be done +depends on the image file format you chose but in general the two magnificent software tools *exiftool* anf *ffmpeg* +are the solution. In case you are using the MarIQT software, these tools are used under the hood. + +### Hash +We use hashes to document the integrity of the image files. A hash is like a fingerprint of the file as it is +computed from the file's byte content. If you like, it is a massive compression of the file's data into a short, +cryptic text (ca. 32 characters) but unlike a zip file there is no way to uncompress the file from the hash. Using +hashes allows us to make sure that a file has not gone corrupt or that a particular file is actually the version we +are interested in. Checking the integrity of a file with hashes requires, that the byte content does not change. It +is therefore absolutely essential, that the UUID is written to the image file's metadata header **before** the hash +for that file is computed! diff --git a/docs/overview/iFDO-overview.md b/docs/overview/iFDO-overview.md new file mode 100644 index 0000000000000000000000000000000000000000..3b1005c68a487dcd990d2bf66f4c612465f4d9cc --- /dev/null +++ b/docs/overview/iFDO-overview.md @@ -0,0 +1,63 @@ +# Introduction +Achieving FAIRness and Openness of (marine) image data requires structured and standardised metadata on the image +data itself and the visual and semantic image data content. This metadata shall be provided in the form of FAIR +digital objects (FDOs). These documentation pages describes how FDOs for images (aka iFDOs) shall be structured. If +you want, an iFDO is a human and machine-readable file format for an entire image set, except that it does not +contain the actual image data, only references to it through persistent identifiers! +iFDOs consist of various metadata fields. Some are required, some are recommended, some are optional. You will only +achieve FAIRness of your image data with the required iFDO core fields populated. You will only gain visibility and +credit for your image data with the recommended capture fields populated. And you will only have awesome image data +in case you also populate the content fields. As a bonus you can add your own domain-specific optional fields. + +# iFDO - image FAIR Digital Object +Marine image data collections need a set of standardized metadata to achieve FAIRness of the data for open +publication. An entire image set (e.g. deployment, station, dive, mission) requires information on the ownership and +allowed usage of the collection. Numerical metadata is required for each image on its acquisition position. It is +recommended to provide further optional metadata based on the imaging use case. The iFDO standard defines a format +to structure such metadata. It was developed by the MareHub working group and the Marine Imaging Community. The +future of iFDOs is described in the [roadmap](../governance.md). + +### Quick facts: +- iFDOs are made for photos ([still images](http://purl.org/dc/dcmitype/StillImage)) and videos ([moving images](http://purl.org/dc/dcmitype/MovingImage)) +- iFDOs consist of an `image-set-header` an `image-set-items` [part](#ifdo-parts) +- iFDOs group metadata fields in three semantic [sections](#ifdo-sections): iFDO core, iFDO capture and iFDO content +- iFDO [core](iFDO-core.md) fields are mandatory +- iFDO [capture](iFDO-capture.md) and [content](iFDO-content.md) fields are optional but recommended +- iFDO fields can be [mapped](../standard/{latest_version}/documentation/iFDO_vocabulary-term-mapping.md) to many other metadata standards +- iFDOs make image data [FAIR](../FAIR-marine-images.md) without requiring them to be open, access-restriction remains possible +- iFDO field names use [kebab-case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case) +- The iFDO documentation is written with Python implementation in mind +- A peer-reviewed manuscript on iFDOs is available at Nature Scientific Data: https://doi.org/10.1038/s41597-022-01491-3 + +### iFDO files +All image metadata shall be stored in one image FAIR digital object (iFDO) file. This file shall contain all iFDO +metadata fields. The file should be human and machine-readable, hence *.json format is recommended. The file name +should be unique, we recommend: `<image-project>_<image-event>_<image-sensor>`_iFDO.json. iFDO files have to be +well-formatted according to the documentation on these pages. They are light-weight and can evolve along their +lifecycle. + + +### iFDO parts +An iFDO file consists of two parts: the `image-set-header` part and the `image-set-items` part. The header part +contains default values for all items. The items part contains all values that deviate from the default values for +this specific image item. The `image-set-header` part is a `object` within which each metadata field is referenced +by a key term such as `image-set-uuid`. The `image-set-items` part is also a `object`, where the keys are the +filenames of the images (i.e. photos or videos). All metadata of an image-item is provided in a list. For still +images (aka photos) this list has only one object as an entry. For videos, the first entry of the list contains an +object of those metadata fields that are defaults for the entire video. All subsequent list entries correspond to +specifications of the metadata for one given time point of the video. + +### iFDO sections +The iFDO standard defines three different section that cover different aspects of FAIRness and target increasing +usability of the image metadata. The [iFDO core](iFDO-core.md) section contains the required metadata that makes +image data sets FAIR. The [iFDO capture](iFDO-capture.md) section contains metadata fields that describe how the +image data was created. The [iFDO content](iFDO-content.md) section describes what is going on in the image data in +terms of information or annotations. These sections to not appear in the iFDO file itself. They represent a virtual +grouping of metadata fields used in the documentation. + + +### Mapping to other image metadata standards +The iFDOs standard aspires to be the most complete standard that allows to bridge between existing standards (like +DublinCore, Audubon, SmartarID, PDS4) while filling gaps among those. We maintain a [term mapping](../standard/{latest_version}/documentation/iFDO_vocabulary-term-mapping.md) of vocabulary terms to other standards. + + diff --git a/docs/resources/sheets/Detailed-iFDO-metadata-collection.xlsx b/docs/resources/sheets/Detailed-iFDO-metadata-collection.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..52b8d96b90a9079caa3c9535ad56e057c9d407c2 Binary files /dev/null and b/docs/resources/sheets/Detailed-iFDO-metadata-collection.xlsx differ diff --git a/docs/resources/sheets/Overview-iFDO-metadata-collection.xlsx b/docs/resources/sheets/Overview-iFDO-metadata-collection.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..48b8ebfe6fdab966b75df8d1696bf67e7a151934 Binary files /dev/null and b/docs/resources/sheets/Overview-iFDO-metadata-collection.xlsx differ diff --git a/docs/roadmap.md b/docs/roadmap.md deleted file mode 100644 index 904cfeea4175637f091d7d5165bed13d8829adce..0000000000000000000000000000000000000000 --- a/docs/roadmap.md +++ /dev/null @@ -1,24 +0,0 @@ -# Governance -Over its first year of existence, the iFDO format was developed by members of the MareHub working group on Images/Videos and through the HGF/INF/HMC-funded project FDO-5DI of DLR and GEOMAR. Additional input was collected from the international marine imaging community. As the next step, a steering board of up to ten members from academia, industry and governance and with international representation shall be assembled at the upcoming Marine Imaging Workshop (10/2022). Please write an e-mail to tschoening@geomar.de in case you are interested to join the steering board. The steering board will then create a statute for the future development of the iFDO format over half a year (ca. 04/2023). - -# Roadmap of iFDO development - -## Upcoming versions - -### v2.0.0 -Should include: -- provenance mechanism -- unit names in field names for lat,lon,depth,... (TBD!) -- stereo imagery -- possibility to encode parts of the iFDO file in binary - -### v1.2.0 -Additional fields to reference information from iFDOs in external resources (e.g. equipment database). - -## Current version v1.1.0 -Updated fields and more detailed, consistent and specific documentation. - -## Previous versions - -### v1.0.0 -Initial publication of the iFDO concept through the repository at https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images and with static supplementary material published as OceanBest Practice (https://hdl.handle.net/11329/1781 and https://hdl.handle.net/11329/1782). diff --git a/docs/sops/conventions/file-formats.md b/docs/sops/conventions/file-formats.md index c8693a191c41cfeacd01402731b6384422404a45..d2992a52a5a8fd47a11544a08bc059d297cd137d 100644 --- a/docs/sops/conventions/file-formats.md +++ b/docs/sops/conventions/file-formats.md @@ -1,43 +1,49 @@ # File format recommendations for image and video SOPs -We recommend to store all relevant information on the image curation process in a human and machine-readable format. For structured information, we recommend the *.yaml format which is compact (i.e. helps with fast transfer across networks), well-formed (i.e. helps with automating curation tasks), and natively supported by OSs and editors. For tabular data, we recommend to use *.txt files. +We recommend to store all relevant information on the image curation process in a human and machine-readable format. +For structured information, we recommend the *.json format which is compact (i.e. helps with fast transfer across +networks), well-formed (i.e. helps with automating curation tasks), and natively supported by OSs and editors. For +tabular data, we recommend to use *.txt files. ## *.txt files -Encoding ASCII information in *.txt files still needs a clear format description. The following is being used throughout the MareHub AGV/I tools: +Encoding ASCII information in *.txt files still needs a clear format description. The following is being used +throughout the iFDO tools: - The file may contain optional comment lines anywhere. These have to begin with the # symbol. Content of those lines is ignored while reading the files. - The first non-comment line of a file must contain the column headers. - Columns are split by the TAB character (\t, chr(9)). - Rows are split by the line feed character (\n, chr(10)). -- Columns that correspond to the MareHub AG V/I metadata vocabulary have to exactly match the vocabulary terms. +- Columns that correspond to the iFDO metadata vocabulary have to exactly match the vocabulary terms. - The file is ASCII/UTF8 encoded plain text. -## *.yaml files -- Need to follow the general *.yaml specification. -- Key or values that correspond to the MareHub AG V/I metadata vocabulary have to exactly match the vocabulary terms. +## *.json files +- Need to follow the general *.json specification. +- Key or values that correspond to the iFDO metadata vocabulary have to exactly match the vocabulary terms. - The file is ASCII/UTF8 encoded plain text. # Examples -## Example *.yaml file -``` -SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg: - image-longitude: -123.854637 - image-latitude: 42.133426 - image-depth: 4230.3 - image-pixel-per-millimeter: 12.1 - image-meters-above-ground: 1.3 - image-coordinate-uncertainty: 4.2 -SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg: - image-longitude: -123.854638 - image-latitude: 42.133427 - image-depth: 4230.4 - image-pixel-per-millimeter: 12.1 - image-meters-above-ground: 1.4 -SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg: - image-longitude: -123.854639 - image-latitude: 42.133428 - image-depth: 4230.5 - image-pixel-per-millimeter: 12.0 - image-meters-above-ground: 1.5 +## Example *.json file +``` +{ + "SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg": { + "image-longitude": -123.854637, + "image-latitude": 42.133426, + "image-altitude-meter": -4230.3, + "image-pixel-per-millimeter": 12.1, + "image-meters-above-ground": 1.3, + "image-coordinate-uncertainty": 4.2 + "SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg": { + "image-longitude": -123.854638 + "image-latitude": 42.133427 + "image-altitude-meter": -4230.4 + "image-pixel-per-millimeter": 12.1 + "image-meters-above-ground": 1.4 + "SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg": { + "image-longitude": -123.854639 + "image-latitude": 42.133428 + "image-altitude-meter": -4230.5 + "image-pixel-per-millimeter": 12.0 + "image-meters-above-ground": 1.5 +} ``` ## Example *.txt file @@ -51,15 +57,14 @@ SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg -123.854639 42.133428 4230.5 12.0 ``` # Important files in the image curation process -There are some information in the image curation process that need to be available to facilitate FAIRness of the imagery. In the end, it is the [iFDO](../../ifdos/iFDO-overview.md) that provides this functionality but on the way to creating the iFDO the curation workflow may create intermediate information files. How those look is very much up to your individual data curation processes and tools. Anyhow we define some essential files here which are used in the software packages provided by the AG V/I. - -## Important *.yaml files -- Project curation file -- [iFDO](../../ifdos/iFDO-overview.md) -- Processing [provenance](provenance-documentation.md) file +There are some information in the image curation process that need to be available to facilitate FAIRness of the +imagery. In the end, it is the [iFDO](../../overview/iFDO-overview.md) that provides this functionality but on the way +to creating the iFDO the curation workflow may create intermediate information files. How those look is very much up +to your individual data curation processes and tools. Anyhow, we define some essential files here which are used in +the software packages to process iFDOs. ## Important *.txt files -First, please note that its not required that you create all these files! In case you can directly create the [iFDO](../../ifdos/iFDO-overview.md) that is also fine. We just found that its helpful to keep these intermediate files available as well. +First, please note that its not required that you create all these files! In case you can directly create the [iFDO](../../overview/iFDO-overview.md) that is also fine. We just found that its helpful to keep these intermediate files available as well. ### Still image navigation file ``` @@ -68,7 +73,7 @@ SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg -123.854637 42.133426 4230.3 12.3 SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg -123.854638 42.133427 4230.4 13.1 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-navigation.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-navigation.txt` ### Moving image navigation file ``` @@ -77,7 +82,7 @@ SO268-1_21-1_GMR_CAM-42_20190513_111213.mp4 0 -123.854637 42.133426 4230.3 SO268-1_21-1_GMR_CAM-42_20190513_111213.mp4 1 -123.854638 42.133427 4230.4 13.1 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-navigation.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-navigation.txt` ### Image UUID file ``` @@ -86,7 +91,7 @@ SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg 9999ba88-1a20-4efe-a0ac-6b4233490ad6 SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg 1c266c00-33e7-4e69-bc9a-f90fb1bce6d0 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-uuids.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-uuids.txt` ### Image acquisition start time file ``` @@ -95,7 +100,7 @@ SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg 2019-05-13 13:14:15.0000 SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg 2019-05-13 13:14:16.0000 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-start-times.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-start-times.txt` ### Image scaling file ``` @@ -104,7 +109,7 @@ SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg 12.1 SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg 12.1 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-scaling.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-scaling.txt` ### Image SHA256 hash file ``` @@ -113,7 +118,7 @@ SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg 83f30eb35d1325c44c85fba0cf478825c0a6 SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg 27c3585560f93a78995a038b5970a002315d2b525b999a24a1d13a5c5e5520f6 ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-hashes.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-hashes.txt` ### Image content feature file ``` @@ -123,4 +128,4 @@ SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg: 0.657 4223 [29,233,61] [39,17,1 SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg: 0.632 2342 [31,231,57] [39,17,17,13,...] ... ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-features.txt` +_When working with the [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/intermediate/<event>_<sensor>_image-features.txt` diff --git a/docs/sops/conventions/folder-structure.md b/docs/sops/conventions/folder-structure.md index 6663ba78598dc041df561a27129327398cacd9f3..69b5e329face29e7db80306961fec79b117043dc 100644 --- a/docs/sops/conventions/folder-structure.md +++ b/docs/sops/conventions/folder-structure.md @@ -1,5 +1,7 @@ ## Folder Structure: -How to structure data on disk should not be enforced by any SOP. Anyhow, we recommend the following structure to aid the automation of data curation and publication workflows. It is based on several best-practices guides (e.g. https://github.com/drivendata/cookiecutter-data-science). +How to structure data on disk should not be enforced by any SOP. Anyhow, we recommend the following structure to aid +the automation of data curation and publication workflows. It is based on several best-practices guides (e.g. +https://github.com/drivendata/cookiecutter-data-science). ``` /<volume>/<project>/ @@ -17,7 +19,10 @@ How to structure data on disk should not be enforced by any SOP. Anyhow, we reco ├── <sensor_x> └── <sensor_z> ``` -On German research vessels, the "scientists folder" on the network or the new "Mass-Data-Module" (MDM, installed in 2021) will mostly act as the root folder `/<volume>/<project>/` but for some researchers, who bring their own mass storage or NAS devices, it may be some path on their own hardware. Some disciplines/groups like to split their data by sensor first. This is not recommended but certainly possible. In that case, the paths would look like this: +On German research vessels, the "scientists folder" on the network or the "Mass-Data-Module" (MDM) +will mostly act as the root folder `/<volume>/<project>/` but for some researchers, who bring their own mass storage +or NAS devices, it may be some path on their own hardware. Some disciplines/groups like to split their data by +sensor first. This is not recommended but certainly possible. In that case, the paths would look like this: ``` /<volume>/<project_i>/ ├── <sensor_x> diff --git a/docs/sops/conventions/provenance-documentation.md b/docs/sops/conventions/provenance-documentation.md index 85ab377ce95bdd86899a61ce356d36686717ea2f..92678db19d3921fcf8158ecb4479d30488a9dc7f 100644 --- a/docs/sops/conventions/provenance-documentation.md +++ b/docs/sops/conventions/provenance-documentation.md @@ -1,28 +1,52 @@ ## Provenance documentation: -Provenance documentation of (automated) SOP steps is required to enable reusability of data and validity checks. Provenance information needs to document the agent, entities and activities and should facilitate reproducibility but mainly document execution steps rather than enable the fully-automated re-execution which would further require the automated setup of the software environment (e.g. through Docker). Provenance of individual SOP steps should be recorded in a machine-readable fashion (i.e. a **yaml** file) like so: +Provenance documentation of (automated) SOP steps is required to enable reusability of data and validity checks. +Provenance information needs to document the agent, entities and activities and should facilitate reproducibility +but mainly document execution steps rather than enable the fully-automated re-execution which would further require +the automated setup of the software environment (e.g. through Docker). Provenance of individual SOP steps should be +recorded in a machine-readable fashion (e.g. in a JSON file). The w3-prov standard defines how provenance +information can be stored, however this format is rather complex and was defined at a time when FAIRness was not +around. At present, we know of no ideal provenance format but of course the prerequisites that the actors, +activities and entities of the provenance workflow should be recorded remains true. + +One possibility for FAIR marine images is to use the ``image-provenance`` field and/or to store an additional +machine-readable provenance file next to the image data. Such a file could look like this: ``` -provenance: - - executable: - name: <executable name> - version: <version string of executable> - parameter: - - name: <param-x_name> - value: <param-x_value> - [hash: <md5 hash of file at <param-x_value> (optional, only for files)>] - - name: <param-y_name> - value: <param-y_value> - log: all the logging information from the executable - hashes: null - time: <time of execution: in utc, human-readable, with milliseconds (%Y%m%d %H:%M:%S.%f)> - - executable: - ... - parameter: - ... - log: - ... - hashes: <md5 hashes of previous provenance file> - time: ... +{ + "provenance": + "executables": [ + { + "name": <executable name> + "version": <version string of executable> + "parameters": [ + { + "name": <param-x_name> + "value": <param-x_value> + "hash": <md5 hash of file at <param-x_value> (optional, only for files)> + }, + { + "name": <param-y_name> + "value": <param-y_value> + }] + "log": all the logging information from the executable + "hashes": null + "time": <time of execution: in utc, human-readable, with milliseconds (%Y%m%d %H:%M:%S.%f)> + }, + { + ... + "parameter": + ... + "log": + ... + "hashes": <md5 hashes of previous provenance file> + "time": ... + } + } + } +} ``` -_When working with the AGV/I [folder structure](folder-structure.md) place this file at:_ `/<volume>/<project>/<event>/<sensor>/protocol/<event>_<sensor>_provenance-<executable name>-<datetime>.yaml` +_When working with the [folder structure](folder-structure.md) place this file at:_ +`/<volume>/<project>/<event>/<sensor>/protocol/<event>_<sensor>_provenance-<executable name>-<datetime>.json` -In case an additional processing step applied to a entity, the additional provenance information shall be appended to the provenance file of the entities' creation. Together with the SHA256 hash of the previous provenance file, a blockchain-like behaviour is enabled. +In case an additional processing step applied to a entity, the additional provenance information shall be appended +to the provenance file of the entities' creation. Together with the SHA256 hash of the previous provenance file, a +blockchain-like behaviour is enabled. diff --git a/docs/versions.md b/docs/versions.md deleted file mode 100644 index a72ac660f299442a34a3cbf101310df442cd22a2..0000000000000000000000000000000000000000 --- a/docs/versions.md +++ /dev/null @@ -1,16 +0,0 @@ -# Current version - v1.1.0 -The state of the repository and documentation represents the current state-of-the-art of the iFDO standard. The current version as documented here is v1.1.0. The version of an iFDO can be specified by the `image-set-ifdo-version` field in the `image-set-header` part. - -# Changelog - -### v1.0.0 -> v1.1.0 -- Added the required `image-set-ifdo-version` field as an `image-set-header`-only field of the iFDO core section -- Dropped the optional `image-pixel-per-millimeter` field from the iFDO capture section due to redundancy with `image-area-square-meter` field (you can keep using it if you like but tools might not understand it anymore) -- Renamed `image-resolution` in iFDO capture section to `image-pixel-magnitude` to avoid ambiguity -- Added the optional `image-datetime-format` field to specify non-standard date formats -- Added the `image-annotations:labels:created-at` field as an ISO8601 datetime of an annotation -- Corrected wrong data types in `image-camera-pose` subfields. -- Modified the description texts (on using iFDO usage for video, image pixel coordinates, annotation confidence, ) -- specified field data types consistenly -- Added a roadmap of the iFDO development - diff --git a/mkdocs.yml b/mkdocs.yml index 8504074f562d1af4fe78734282cbd38bbfa447d9..8ebd8cf9cf8d191c4ecaccfb17352f5d969e4e5c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,7 @@ site_name: FAIR marine images strict: true repo_name: Edit Source repo_url: https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images -edit_uri: https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/edit/master/docs +edit_uri: https://gitlab.hzdr.de/datahub/marehub/ag-videosimages/fair-marine-images/-/edit/v2.0.0/ theme: name: material sticky-navigation: true @@ -14,35 +14,7 @@ theme: plugins: - search - macros -# - with-pdf: -# author: MareHub AG Images -# copyright: Released under CC-0 -# cover_title: FAIR Marine Images -# cover_subtitle: with image FAIR Digital Objects -# toc_title: FAIR Marine Images - #excludes_children: - # - 'sops/' - # - 'release-notes/:changelog' - # -# exclude_pages: -# - 'sops/' - # - 'appendix/contribute/' - #convert_iframe: - # - src: IFRAME SRC - # img: POSTER IMAGE URL - # text: ALTERNATE TEXT - # - src: ... - #two_columns_level: 3 - # - #render_js: true - #headless_chrome_path: headless-chromium - # -# output_path: FAIR-marine-images.pdf - #enabled_if_env: ENABLE_PDF_EXPORT - # - #debug_html: true - #show_anchors: true - #verbose: true + markdown_extensions: - smarty - toc: @@ -51,24 +23,49 @@ markdown_extensions: - admonition - def_list extra_css: [extra.css] +hooks: + - "scripts/hooks/load_standard_files.py" + - "scripts/hooks/process_nav_template.py" + - "scripts/hooks/generate_schema_doc.py" nav: - Introduction: - What is FAIR?: 'index.md' - What are FAIR marine images?: 'FAIR-marine-images.md' - iFDOs: - - Overview: 'ifdos/iFDO-overview.md' - - iFDO format: - - iFDO Core: 'ifdos/iFDO-core.md' - - iFDO Capture: 'ifdos/iFDO-capture.md' - - iFDO Content: 'ifdos/iFDO-content.md' - - Ressources: - - iFDOs vs. other metadata formats: 'ifdos/iFDO_vocabulary-term-mapping.md' - - Icons for fixed iFDO fields: 'ifdos/iFDO-icons.md' - - iFDO to HTML converter: 'ifdos/ifdo-visualization.md' - - Roadmap: roadmap.md + - Overview: + - iFDO: 'overview/iFDO-overview.md' + - iFDO Core: 'overview/iFDO-core.md' + - iFDO Capture: 'overview/iFDO-capture.md' + - iFDO Content: 'overview/iFDO-content.md' + - Standard: + - "{version}": + - Documentation: + - iFDO Structure: 'standard/{version}/documentation/iFDO-structure.md' + - iFDO Core: 'standard/{version}/documentation/iFDO-core.md' + - iFDO Capture: 'standard/{version}/documentation/iFDO-capture.md' + - iFDO Content: 'standard/{version}/documentation/iFDO-content.md' + - Context: 'standard/{version}/documentation/iFDO_vocabulary-term-mapping.md' + - Examples: + - Image Example: 'standard/{version}/examples/ifdo-image-example.json' + - Video Example: 'standard/{version}/examples/ifdo-video-example.json' + - Schema: + - iFDO: 'standard/{version}/schema/ifdo.json' + - iFDO Core: 'standard/{version}/schema/ifdo-core.json' + - iFDO Content: 'standard/{version}/schema/ifdo-content.json' + - iFDO Capture: 'standard/{version}/schema/ifdo-capture.json' + - Annotation Schema: 'standard/{version}/schema/annotation.json' + - Provenance Schema: 'standard/{version}/schema/provenance.json' + - Icons for iFDO fields: 'standard/{version}/iFDO-icons.md' + - Changelog: 'standard/{version}/changelog.md' + - Governance: governance.md - SOPs (Standard operating procedures): - Overview: 'sops/sop-overview.md' - Folder structure: 'sops/conventions/folder-structure.md' - File formats: 'sops/conventions/file-formats.md' - Provenance documentation: 'sops/conventions/provenance-documentation.md' - Image Curation SOP: 'sops/SOP_image-curation.md' + - iFDO data collection: 'resources/sheets/Overview-iFDO-metadata-collection.xlsx' + - iFDO data collection (detailed): 'resources/sheets/Detailed-iFDO-metadata-collection.xlsx' +watch: + - standard + - docs diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000000000000000000000000000000000000..83d97c76ba0ab2b7bd23abc61777cc685e3f6f98 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,44 @@ +import os + +import nox + +nox.options.default_venv_backend = "uv" + + +def get_examples(directory: str) -> list[str]: + files = os.listdir(directory) + return [os.path.join(directory, file) for file in files] + + +@nox.session(name="Test Examples") +@nox.parametrize(["example_file"], get_examples("standard/examples")) +def test_examples(session, example_file: str): + session.install("jsonschema") + session.run("python", "scripts/test_schema.py", example_file) + + +@nox.session(name="Lint Code") +def lint_generation_code(session): + session.install("ruff") + session.run("ruff", "check") + + +@nox.session(name="Test Schema Generation") +def test_schema_generation(session): + session.install("pytest") + session.run("pytest", "scripts/hooks/generation/") + session.notify("schema_generation_coverage") + + +@nox.session() +def schema_generation_coverage(session): + session.install("pytest", "pytest-cov") + session.run( + "pytest", + "scripts/hooks/generation/", + "--cov=scripts/hooks/generation", + "--cov-report", + "term", + "--cov-report", + "html", + ) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..bd40c518248c09224ea9622ee8ec73479b2bcce7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[project] +name = "fair-marine-images" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "nox>=2024.10.9", + "mkdocs>=1.6.1", + "mkdocs-build-plantuml-plugin>=1.9.0", + "mkdocs-macros-plugin>=1.3.7", + "mkdocs-material>=9.5.49", + "weasyprint>=63.1", + "jsonschema>=4.23.0", + "pyyaml>=6.0.2", + "gitpython>=3.1.44", +] diff --git a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_capture.yaml b/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_capture.yaml deleted file mode 100644 index 91e97f4b8399c725201c2ac0d6cbe6c0fa6a7b97..0000000000000000000000000000000000000000 --- a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_capture.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Warning: this is not a valid iFDO file! It is just a collection of iFDO capture fields that could appear in a valid iFDO. -image-set-header: - image-acquisition: photo - image-set-quality: raw - image-deployment: survey - image-navigation: beacon - image-scale-reference: laser marker - image-illumination: artificial light - image-resolution: mm - image-marine-zone: seafloor - image-spectral-resolution: rgb - image-bit-resolution: 8 - image-target-environment: Intertidal mud flats - image-spatial-contraints: Low-tide prevented accessing the entire target area, transect length had to be reduced to 80 percent. -image-set-items: - SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg: - - image-area-square-meter: 4.3 - image-meters-above-ground: 2.1 - image-camera-housing-viewport: - viewport-type: domeport - viewport-optical-density: 0.3 - viewport-thickness-millimeter: 17 - - diff --git a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_content.yaml b/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_content.yaml deleted file mode 100644 index 609522aee67202fb92b6fc4ae6dbce4121c3e584..0000000000000000000000000000000000000000 --- a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_content.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# Warning: this is not a valid iFDO file! It is just a collection of iFDO content fields that could appear in a valid iFDO. -image-set-header: - image-annotation-labels: - - id: 124731 - name: Kolga hyalina - info: http://www.marinespecies.org/aphia.php?p=taxdetails&id=124731 - - id: 423349 - name: Elpidia heckeri - info: http://www.marinespecies.org/aphia.php?p=taxdetails&id=423349 - image-annotation-creators: - - id: 0000-0002-0035-3282 - name: Timm Schoening - type: non-expert - - id: 0000-0001-5427-0151 - name: Autun Purser - type: expert -image-set-items: - SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg: - image-entropy: 0.475 - image-particle-count: 1342 - image-average-color: [27,245,64] - image-mpeg7-features: - ColorLayoutDescriptor: [24,16,17,14,16,8,16, ...] - ColorStatisticDescriptor: [21,242,24,251,6,255, ...] - ColorStructureDescriptor: [0,0,0,0,0,2,0,0,...] - DominantColorDescriptor: [2,27,9,8,11,9,9,...] - EdgeHistogramDescriptor: [1,0,4,3,3,2,2,...] - HaralickTextureDescriptor: [-691448832.0,1.262,-354064896.0,...] - HistogramColorDescriptor: [1.2755102034134325e-05,2.4155506864190102e-02,...] - HomogeneousTextureDescriptor: [71,13,122,150,153,138,146,...] - ScalableColorDescriptor: [-129,146,-51,49,...] - SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg: - image-entropy: 0.657 - image-particle-count: 4223 - image-average-color: [29,233,61] - image-annotations: - - coordinates: [13,42] - labels: - - label: 124731 - annotator: 0000-0002-0035-3282 - - label: 124731 - annotator: 0000-0001-5427-0151 - - coordinates: [123,567,32] - labels: - - label: 124731 - annotator: 0000-0001-5427-0151 - ... - SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg: - image-entropy: 0.632 - image-particle-count: 2342 - image-average-color: [31,231,57] - ... diff --git a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_core.yaml b/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_core.yaml deleted file mode 100644 index c8485b933a2958d09012a7a8a52ca45014c60e96..0000000000000000000000000000000000000000 --- a/resources/SO268-1_021-1_GMR_CAM-23_example-iFDO_core.yaml +++ /dev/null @@ -1,34 +0,0 @@ -image-set-header: - image-set-uuid: 2a2360e9-a5ec-4ad2-be04-0ea0b4cbdc58 - image-set-name: SO268-1_21-1_GMR_CAM-23 - image-set-handle: 20.500.12085/2a2360e9-a5ec-4ad2-be04-0ea0b4cbdc58@data - image-context: Mining Impact 2 - image-project: SO268-1 - image-event: 21-1 - image-platform: SO_OFOS-1 - image-sensor: GMR_CAM-23 - image-coordinate-reference-system: EPSG:4326 - image-creators: - - name: T. Bodur - orcid: 0000-0002-1825-0097 - image-pi: {name: T. Bodur, orcid: 0000-0002-1825-0097} - image-license: CC-BY - image-coordinate-uncertainty: 13.42 -image-set-items: - SO268-1_21-1_GMR_CAM-23_20190513_131415.jpg: - - image-uuid: 9999ba88-1a20-4efe-a0ac-6b4233490ad6 - image-hash-sha256: 83f30eb35d1325c44c85fba0cf478825c0a629d20177a945069934f6cd07e087 - image-datetime: 2019-05-13 13:14:15.0000 - image-longitude: -123.854637 - image-latitude: 42.133426 - image-depth: 4230.3 - image-coordinate-uncertainty: 4.2 - SO268-1_21-1_GMR_CAM-23_20190513_131416.jpg: - - image-uuid: 1c266c00-33e7-4e69-bc9a-f90fb1bce6d0 - image-hash: 27c3585560f93a78995a038b5970a002315d2b525b999a24a1d13a5c5e5520f6 - image-datetime: 2019-05-13 13:14:16.0000 - image-longitude: -123.854638 - image-latitude: 42.133427 - image-depth: 4230.4 - SO268-1_21-1_GMR_CAM-23_20190513_131417.jpg: - ... diff --git a/resources/iFDO.xlsx b/resources/iFDO.xlsx deleted file mode 100644 index 699bee23de921410b786b5f37fe333a28a6d2599..0000000000000000000000000000000000000000 Binary files a/resources/iFDO.xlsx and /dev/null differ diff --git a/resources/sops/sop-figures/SOP_ImageCuration_v0.9.0_overview.png b/resources/sops/sop-figures/SOP_ImageCuration_v0.9.0_overview.png deleted file mode 100644 index b255c9a2effcef20dd9fb35b4f5d0c885582e0bb..0000000000000000000000000000000000000000 Binary files a/resources/sops/sop-figures/SOP_ImageCuration_v0.9.0_overview.png and /dev/null differ diff --git a/resources/sops/sop-image-curation.md b/resources/sops/sop-image-curation.md deleted file mode 100644 index 8d47ccb01dcb2a60bcfce1c708661ac0b49cc653..0000000000000000000000000000000000000000 --- a/resources/sops/sop-image-curation.md +++ /dev/null @@ -1,153 +0,0 @@ -# SOP: Image curation and publication - -*Synopsis:* *The **purpose** of this Standard Operating Procedure (SOP) is to generally describe how to **publish marine research image data** such as photos and videos for scientific use. The **goal** of this document is to **enable all scientists to provide FAIR and open image data** using the infrastructure available to them. -The **scope** of this SOP includes the steps necessary to **make existing images** (photos and videos) **available** to open scientific use **after acquisition**. This includes a) providing a core set of image metadata, b) saving files and metadata in a central storage location with backup and long-term archival, c) disclosure of image existence through public databases by publishing the image metadata, d) enabling access to image data for authorized stakeholders, e) enabling scientific interpretation of images, and f) FAIR and open publication of the image data itself. Completing the SOP will **result** in **well-curated image data that adheres to open standards**.* - -### Overview - - - -Overview of a generic image curation and publication procedure. In blue: processes and process documentation, in green: data entities, in yellow: infrastructure to manage image data. The infrastructures can be access-controlled (key symbol) or public. The image acquisition is the sole responsibility of the scientists. Ideally, an RDM team provides support for executing the workflow steps. The supplement material of this SOP provides templates for acquisition protocols and data management plans. Each image acquisition should trigger an independent execution of the SOP workflow. That means that for each acquisition – i.e. image data set – also an acquisition protocol, an iFDO, and data processing report are created. The iFDO metadata format and file facilitate FAIRness of the image data. Creating a valid, quality-controlled iFDO is the most important part of the workflow. - -## Preparation phase - -#### 1. _Scientists_ create a data management plan as a living document -**When**: Before project start -**How**: Place a ```docx file in a cloud folder``` that all project partners can access. -**Why**: For AR of FAIR - Almost all third-party funding nowadays requires fundees to maintain a data management plan (DMP). This is a living document that ideally starts its life cycle before handing in a research proposal and is continuously updated until beyond the project lifetime to document the data lifecycle. Image data that is being acquired needs to be documented in the DMP. The supplement of this SOP contains an example DMP for image data. - -#### 2. _Scientists_ collect basic project information in machine-readable format -**When**: Before image acquisition -**How**: Place a ```json/yaml file in a Git repositor``` that all data stakeholders can access. -**Why**: For FR of FAIR - To create an iFDO, information about the context of the image acquisition, i.e. the project information, is required once. This information can be copied e.g. from the proposal or a cruise’s web information. Required are the following fields image-project (Number / name of the project or experiment within which these images were created. Could be a cruise number, e.g. “SO268â€); image-context (Wider context of the project or experiment or cruise, e.g. “Mining Impact 2â€); and image- pi (Full name, email and ORCID of principal investigator (project lead), not necessarily the data creators.). - -## Acquisition phase - -#### 3. _Scientists_ document each image acquisition by an acquisition protocol. -Result: A PDF alongside the images on an external disk. -Info: Detailed digital documentation of each image acquisition is crucial. This includes core information on the gear -used as well as information on the intent to acquire the images. The acquisition protocol should be made -available publicly in digital format (e.g. as a scan or photo of the manually populated sheet). -Tip: See supplement to this document for a template. - -#### 4. Scientists acquire images, navigation data and metadata. -Result: Terabytes of images on an external disk. -Info: Acquiring image data is the sole responsibility of the scientists. You know how to best acquire data for your -research purposes. You know the procedures, the best-practices, the optimal settings. The RDM team will not -interfere with your proven scientific demands. -Tip: If you assume there is potential for improvement of your image acquisition procedures, you can ask the MareHub -working group on Videos/Images or the international Marine Imaging Community for input. - -#### 5. Scientists structure the data. à FAIR -Result: Data is stored in a consistent file and folder structure on disk. -Info: Keeping track of data in the future is supported by a consistent file naming scheme and folder structure. You -can create your own, but then stick to it for all your data. -Tip: See supplement to this document for a recommended folder structure template. - -#### 6. Scientists curate the image data. à FAIR -Result: Terabytes of properly named images, containing a UUID metadata value, stored on a network drive. -Info: Image data is huge and unstructured. Name image files properly, ideally already during acquisition. A valid -image name includes at least an identifier of the acquisition event (usually including the project number), an -identifier of the sensor used for acquisition and the UTC date and time of acquisition. -An example could be: SO268-1_21-1_OFOS_SO_CAM-1_20190304_083834.JPG where the red part is the -event including the project, the blue part is the sensor identifier and the grey part is the date and time information. -To make images FAIR, it is also essential, that each image file contains one specific value in its metadata -header: a random UUID which uniquely identifies the specific file. You can create this UUID yourself. -You should also consider removing images from your data set that were taken during pre-acquisition checks or -with erroneous settings that led to corrupt data. No need to publish those but don’t be too strict, other users -might still be interested in the data. -Tip: To make working with big image data more manageable, split huge video files to chunks (e.g. of 15 minutes -length) and split huge image folders to subfolders (e.g. thousand files per subfolder). Your operating system and -analysis software speeds will increase. - -#### 7. Scientists curate the navigation data. à FAIR -Result: A machine-readable file (yaml, json, xml, csv, ...) containing curated 4D navigation data for each photo or -second of a video, stored alongside the curated image data. -Info: All FAIR image data needs 4D acquisition coordinates (3D spatial, 1D temporal) and an estimate of the spatial -coordinate uncertainty. Times must always be given in UTC. Images of experiments in the lab are assigned the -location of the lab. Images of samples are assigned the sampling location. Images of fixed observatories are -assigned a fixed coordinate. Images of moving platforms are assigned a varying coordinate. Should underwater -navigation not be available use the next-best estimate (e.g. ship coordinate). Quantification of navigation data -uncertainty is required per image. As raw navigation data is error-prone, a data curation step is essential. - -#### 8. Scientists create an iFDO file for the image data set. à FAIR -Result: A machine-readable file (event_sensor_date_time_iFDO.yaml) containing all metadata for the image -set, stored alongside the curated image data. -Info: This is the most important step to make your images FAIR. See https://marine-imaging.com/fair for details on -iFDOs. And see https://doi.org/10.5281/zenodo.5681429 for a detailed SOP on this specific step. -An iFDO file has to contain two sections: the image-set-header and the image-set-items section. All -metadata that attains the same fixed value for all the images in the data set can be added once to the image- -set-header section. All metadata that attains varying values for the individual images has to be added to the -image-set-items section. The field names in both sections have to follow the standardized iFDO -nomenclature. You can add more fields in case there is none that suits your needs for your specific domain -metadata. The field names in the iFDO are split into three groups: iFDO core, iFDO capture and iFDO content. -The iFDO core fields are required to create a valid iFDO. You have to provide all the metadata values for all -iFDO core fields. The iFDO capture and content groups contain optional, yet recommended metadata fields. -You will only gain visibility and credit for your image data with the recommended capture fields populated. And -you will only have awesome image data in case you also populate the content fields. The capture fields contain -information on how and why the images were created. The content features provide information on the pixel -of semantic content of the images. -Tip: The MarIQT python package and jupyter notebooks provide a lot of functionality to help you create iFDOs for -your data and check their validity. Of course, any other way to create the iFDOs is fine as well. - -#### 9. Scientists create a data processing report. à FAIR -Result: A human-readable file (pdf, yaml, html, ...) containing all information needed to recreate the curated image -and metadata as well as iFDO, stored alongside the curated image data. -Info: The data processing report collects all information that is needed to recreate the curated image data and -curated metadata from the used raw data. In an ideal world this includes the virtual environment used to run -algorithms and the exact versions of this algorithms. In a realistic setting this is a description of the tools and -parameters used of manual interference, of the applied workflow of processing steps and locations of data. -The data processing report needs to be available to data users, so it is essential to make it publicly available. -You have to add it to the dataset upon publication in PANGAEA. -Tip: Base the processing report on this SOP and follow its section structure to prevent re-writing info that is already -here and just link to the DOI of this SOP. That way you can keep your data processing report short. - -#### 10. Scientists update the data management plan. à FAIR -Result: Additional sections in the DMP which is stored as a living document in a cloud. -Info: Update the DMP with all relevant information from the acquisition process and its documentation. - -TODO - -## Publication phase - -#### 11. Scientists publish the iFDO. à FAIR -Result: The iFDO file is publicly available for download. -Info: To make your image data FAIR and public it is essential (and required) to provide access to the metadata early -on. Use a database like OSIS to share your data early on with your project partners. - -#### 12. Scientists publish the navigation data with a web map interface. à FAIR -Result: Image coordinates are available to GIS applications through web interfaces. -Info: GIS applications like QGIS or ArcGIS can access position data through web interfaces like WFS, WMS. Using -such an infrastructure makes it easy to use basic information about image acquisition. - -#### 13. Scientists migrate the image data to a public web server. à FAIR -Result: Curated data is stored with backup in a server infrastructure and accessible through network folders & URLs. -Info: Copy the image data and metadata from your network drive (or external disk) to a publicly accessible server. -Create separate folders for each event / station / deployment / dive / experiment / acquisition. Name these -folders properly to include the project / cruise identifier, and the event identifier. - -#### 14. Scientists make the image data available for analysis (optional). à FAIR -Result: Image data is accessible in an annotation tool for semantic annotation. -Info: Web-based image annotation software, such as BIIGLE, can be used to share image data with others, to mark -objects and regions of interest and to conduct analyses. - -#### 15. Scientists publish image data in PANGAEA (optional). à FAIR -Result: Image data and metadata are migrated to PANGAEA and can be referenced by a DOI. -Info: PANGAEA must physically host the image data to provide a DOI for it. This step is optional and only required -in case you need a DOI for your image data. - -#### 16. Scientists update the data management plan. à FAIR -Result: Additional information in the DMP which is stored as a living document in a cloud. -Info: Provide the remaining information, e.g. DOIs, handles to the data management plan. -Tip: Store a static copy (e.g. a PDF) of the final DMP as a reference for future projects and collaborations. Some -say, this should be published as well. Consider uploading it to Zenodo to make it citeable by DOI. - -TODO - -# Appendix - -## Task table - -TODO - - diff --git a/resources/sops/.gitkeep b/scripts/__init__.py similarity index 100% rename from resources/sops/.gitkeep rename to scripts/__init__.py diff --git a/resources/sops/sop-figures/.gitkeep b/scripts/hooks/__init__.py similarity index 100% rename from resources/sops/sop-figures/.gitkeep rename to scripts/hooks/__init__.py diff --git a/scripts/hooks/doc_inserter.py b/scripts/hooks/doc_inserter.py new file mode 100644 index 0000000000000000000000000000000000000000..12f68206ac14634bd5ff28a8d47992e5467d2191 --- /dev/null +++ b/scripts/hooks/doc_inserter.py @@ -0,0 +1,24 @@ +from typing import Callable + +import regex +from mkdocs.structure.files import Files +from mkdocs.structure.pages import Page + + +class DocInserter(object): + def __init__(self, pattern: str, doc_generator: Callable[[str, Page, Files], str]) -> None: + self._pattern = regex.compile(pattern) + self._doc_generator = doc_generator + + def __call__(self, markdown: str, page: Page, files: Files) -> str: + + matches = self._pattern.findall(markdown) + + if matches is None or len(matches) == 0: + return markdown + + for match in matches: + doc = self._doc_generator(match[1], page, files) + markdown = markdown.replace(match[0], doc) + + return markdown diff --git a/scripts/hooks/generate_schema_doc.py b/scripts/hooks/generate_schema_doc.py new file mode 100644 index 0000000000000000000000000000000000000000..6640e3f12d04d64bb7371796e69dd4c9c7bfc626 --- /dev/null +++ b/scripts/hooks/generate_schema_doc.py @@ -0,0 +1,151 @@ +import json +import os +from io import StringIO + +import yaml +from generation.context.context_doc_generator import ContextDocGenerator +from generation.context.context_doc_options import ContextDocOptions +from generation.icons.icon_doc_generator import IconDocGenerator +from generation.icons.icon_doc_options import IconDocOptions +from generation.schema.requirement_table_generation import RequirementTableGeneration +from generation.schema.requirement_table_generation_options import ( + RequirementTableGenerationOptions, +) +from generation.schema.schema_doc_generator import SchemaDocGenerator +from generation.schema.schema_doc_options import SchemaDocOptions +from generation.schema.schema_references_resolver import SchemaReferencesResolver +from git import Repo +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import Files +from mkdocs.structure.pages import Page + +from doc_inserter import DocInserter + +reference_table = [ + ( + "https://marine-imaging.com/fair/schemas/provenance.json", + "standard/schema/provenance.json", + ), + ( + "https://marine-imaging.com/fair/schemas/annotation.json", + "standard/schema/annotation.json", + ), +] + +OMIT_LATEST = os.environ.get("PROD_ENV") == "1" + + +def on_page_markdown( + markdown: str, page: Page, config: MkDocsConfig, files: Files +) -> str | None: + output = markdown + + for replacer in [ + insert_latest_version_template, + DocInserter(r"(```json-schema-gen\n([^`]*)\n```)", insert_json_schema_doc_gen), + DocInserter(r"(```json-link-req-gen\n([^`]*)\n```)", insert_json_schema_req_gen), + DocInserter(r"(```json-schema-icons-gen\n([^`]*)\n```)", insert_icon_doc_gen), + DocInserter(r"(```json-schema-context-gen\n([^`]*)\n```)", insert_context_doc_gen), + DocInserter(r"(```git-tag-changelog\n([^`]*)\n```)", insert_changelog) + ]: + output = replacer(output, page, files) + + return output + + +def insert_latest_version_template(markdown: str, _page: Page, _files: Files) -> str: + latest_version = "latest" + + if OMIT_LATEST: + latest_version = _get_latest_tag().tag + + result = markdown.replace("{latest_version}", latest_version) + return result + + +def _get_latest_tag(): + repo = Repo(".") + return repo.tags[-1].tag + + + +def insert_json_schema_doc_gen(options: str, page: Page, files: Files) -> str: + schema_resolver = SchemaReferencesResolver.from_reference_table(reference_table) + + config_dict = yaml.safe_load((StringIO(options))) + config = SchemaDocOptions(**config_dict) + + schema = _get_schema_from_files(config.schema, page, files) + resolved_schema = schema_resolver(schema) + + doc = SchemaDocGenerator(config).generate_schema_doc(resolved_schema) + return doc + + +def insert_json_schema_req_gen(options: str, page: Page, files: Files) -> str: + + config_dict = yaml.safe_load((StringIO(options))) + config = RequirementTableGenerationOptions(**config_dict) + + schema = _get_schema_from_files(config.schema_item.split("#")[0], page, files) + remote_schema = _get_schema_from_files(config.remote_schema, page, files) + + table = RequirementTableGeneration(config)(schema, remote_schema) + return table + + +def insert_icon_doc_gen(options: str, page: Page, files: Files) -> str: + schema_resolver = SchemaReferencesResolver.from_reference_table(reference_table) + + config_dict = yaml.safe_load((StringIO(options))) + config = IconDocOptions(**config_dict) + + schema = _get_schema_from_files(config.schema, page, files) + + resolved_schema = schema_resolver(schema) + + icon_path = _get_rel_page_path(config.icon_path, page) + icon_list = [ + os.path.split(file_uri)[1] + for file_uri in files.src_uris.keys() + if file_uri.find(icon_path) != -1 + ] + table = IconDocGenerator(config)(resolved_schema, icon_list) + return table + + +def insert_context_doc_gen(options: str, page: Page, files: Files) -> str: + config_dict = yaml.safe_load((StringIO(options))) + config = ContextDocOptions(**config_dict) + + schema = _get_schema_from_files(config.schema, page, files) + + table = ContextDocGenerator(config)(schema) + return table + + +def _get_schema_from_files(rel_path: str, page: Page, files: Files) -> dict: + internal_path = _get_rel_page_path(rel_path, page) + + schema_file = files.get_file_from_path(internal_path) + if schema_file is None: + raise Exception("Schema file not found") + + return json.loads(schema_file.content_string) + + +def _get_rel_page_path(rel_path: str, page: Page): + page_path = os.path.split(page.file.src_path)[0] + + return os.path.normpath(os.path.join(page_path, rel_path)) + + +def insert_changelog(options: str, page: Page, files: Files) -> str: + repo = Repo(".") + + version = os.path.normpath(page.file.src_path).split(os.path.sep)[1] + if version == "latest": + return "See changes of the latest version at GitLab" + + version_tag = repo.tag(version).tag + return version_tag.message diff --git a/scripts/hooks/generation/__init__.py b/scripts/hooks/generation/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/hooks/generation/context/__init__.py b/scripts/hooks/generation/context/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/hooks/generation/context/context_doc_generator.py b/scripts/hooks/generation/context/context_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..87f5bd9b0bc61f3f608763c020f842f35de8beea --- /dev/null +++ b/scripts/hooks/generation/context/context_doc_generator.py @@ -0,0 +1,81 @@ +import logging +import re +import urllib +from typing import Optional, Tuple + +from .context_doc_options import ContextDocOptions +from ..markdown_table import generate_markdown_table + +logger = logging.getLogger(f"mkdocs.plugins.{__name__}") + + +class ContextDocGenerator: + def __init__(self, config: ContextDocOptions): + self._config = config + + def __call__(self, schema: dict): + if "@context" not in schema: + logger.info(f"No context in schema {self._config.schema}") + return "There is currently not context for these fields." + + properties = schema["properties"] + contexts = schema["@context"] + context_schema_mapping = [ + self._get_context_vocab_definition(context) for context in contexts + ] + + table_header = ["iFDO Field"] + [ + f"[{key}]({value})" for key, value in context_schema_mapping + ] + table_rows = [ + [property_name] + + [ + self._get_formatted_context(property_name, context, schema_mapping[1]) + for context, schema_mapping in zip(contexts, context_schema_mapping) + ] + for property_name in properties.keys() + ] + + return generate_markdown_table(table_header, table_rows) + + @staticmethod + def _get_context_vocab_definition(context: dict) -> Tuple[str, str]: + if "@vocab" in context: + return context["@vocab"], context["@vocab"] + + context_schemas = [ + (key, entry) + for key, entry in context.items() + if ContextDocGenerator.is_url(entry) + ] + if len(context_schemas) != 1: + logger.warning( + "Could not find unique schema definition in context: " + str(context) + ) + + return context_schemas[0] + + @staticmethod + def is_url(input: str) -> bool: + pattern = r"^(http|https):\/\/([\w.-]+)(\.[\w.-]+)+([\/\w\.-]*)*\/?$" + return bool(re.match(pattern, input)) + + @staticmethod + def _get_formatted_context( + property_name: str, context: dict, schema_url: str + ) -> str: + resolved_context = ContextDocGenerator._resolve_context(property_name, context) + if resolved_context is None: + return " - " + + return f"[{resolved_context}]({urllib.parse.urljoin(schema_url, resolved_context)})" + + @staticmethod + def _resolve_context(property_name: str, context: dict) -> Optional[str]: + if property_name not in context: + return None + + if ":" in context[property_name]: + return context[property_name].split(":")[1] + + return context[property_name] diff --git a/scripts/hooks/generation/context/context_doc_options.py b/scripts/hooks/generation/context/context_doc_options.py new file mode 100644 index 0000000000000000000000000000000000000000..fb0c506e5621f111f41df30eed2d814a39baee6a --- /dev/null +++ b/scripts/hooks/generation/context/context_doc_options.py @@ -0,0 +1,6 @@ +from dataclasses import dataclass + + +@dataclass +class ContextDocOptions: + schema: str diff --git a/scripts/hooks/generation/context/test_context_doc_generator.py b/scripts/hooks/generation/context/test_context_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..50b47a4e67b8b08c041e2593b3c07968a8f47253 --- /dev/null +++ b/scripts/hooks/generation/context/test_context_doc_generator.py @@ -0,0 +1,55 @@ +from .context_doc_generator import ContextDocGenerator +from .context_doc_options import ContextDocOptions + + +def test_context_doc_generator_w_vocab(): + options = ContextDocOptions("") + generator = ContextDocGenerator(options) + + schema = { + "type": "object", + "properties": { + "image-name": { + "type": "string", + }, + }, + "@context": [{"@vocab": "http://schema.org", "image-name": "name"}], + } + + result = generator(schema) + + assert ( + result + == """| iFDO Field | [http://schema.org](http://schema.org) | +| ----- | ----- | +| image-name | [name](http://schema.org/name) |""" + ) + + +def test_context_doc_generator_w_link(): + options = ContextDocOptions("") + generator = ContextDocGenerator(options) + + schema = { + "type": "object", + "properties": { + "image-name": { + "type": "string", + }, + }, + "@context": [ + { + "DarwinCore": "https://rs.tdwg.org/dwc/terms/", + "image-name": "DarwinCore:datasetName", + } + ], + } + + result = generator(schema) + + assert ( + result + == """| iFDO Field | [DarwinCore](https://rs.tdwg.org/dwc/terms/) | +| ----- | ----- | +| image-name | [datasetName](https://rs.tdwg.org/dwc/terms/datasetName) |""" + ) diff --git a/scripts/hooks/generation/icons/__init__.py b/scripts/hooks/generation/icons/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/hooks/generation/icons/icon_doc_generator.py b/scripts/hooks/generation/icons/icon_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..00ff4fb9938fb2dede557d72abc36a61e7c8e0b2 --- /dev/null +++ b/scripts/hooks/generation/icons/icon_doc_generator.py @@ -0,0 +1,118 @@ +import logging +from collections import defaultdict +from functools import reduce +from pathlib import Path +from typing import Tuple, List + +from .icon_doc_options import IconDocOptions +from ..markdown_table import generate_markdown_table + +logger = logging.getLogger(f"mkdocs.plugins.{__name__}") + + +class IconDocGenerator: + def __init__(self, config: IconDocOptions): + self._config = config + + def __call__(self, json_schema: dict, icon_file_list: List[str]) -> str: + icon_property_list = [ + tuple(Path(file).stem.split("_")) for file in icon_file_list + ] + icon_property_mapping = reduce( + self._insert_into_mapping, icon_property_list, defaultdict(set) + ) + + table_header = ["Field", "Value", "Icon", "Description"] + properties = self._get_properties_depth_first(json_schema) + + property_rows = [ + self._generate_property_rows( + path, property, icon_property_mapping[self._get_name_from_path(path)] + ) + for path, property in properties + if self._get_name_from_path(path) in icon_property_mapping + ] + rows = reduce(lambda a, b: a + b, property_rows, []) + + return generate_markdown_table(table_header, rows) + + @staticmethod + def _get_properties_depth_first( + json_schema: dict, path: List[str] = None + ) -> List[Tuple[List[str], dict]]: + if path is None: + path = [] + output = [] + for key, value in json_schema["properties"].items(): + if value["type"] == "string": + output.append((path + [key], value)) + + if value["type"] == "object" and "properties" in value: + output += IconDocGenerator._get_properties_depth_first( + value, path + [key] + ) + + if ( + value["type"] == "array" + and "items" in value + and "properties" in value["items"] + ): + output += IconDocGenerator._get_properties_depth_first( + value["items"], path + [key] + ) + + return output + + @staticmethod + def _get_name_from_path(path: List[str]) -> str: + return "-".join(path) + + @staticmethod + def _insert_into_mapping(mapping, value): + mapping[value[0]].add(value[1]) + return mapping + + def _generate_property_rows( + self, path: List[str], property: dict, icons: set[str] + ) -> List[List[str]]: + field_col = f"[{" > ".join(path)}]({self._config.external_property_page}#{self._get_name_from_path(path)})" + icon_list = list(icons) + first_row = [ + self._generate_property_row( + field_col, self._get_name_from_path(path), property, icon_list[0] + ) + ] + rows = [ + self._generate_property_row( + "", self._get_name_from_path(path), property, icon + ) + for icon in icon_list[1:] + ] + + return first_row + rows + + def _generate_property_row( + self, field: str, name: str, property: dict, icon: str + ) -> List[str]: + if "anyOf" not in property: + logger.info(f"Invalid icon: {name}:{icon}. Target property is not an enum") + return [field, icon, self._get_display_icon(name, icon), ""] + + enum_mapping = { + entry["const"]: entry["description"] + for entry in property["anyOf"] + if "const" in entry and "description" in entry + } + + if icon not in enum_mapping: + logger.warning( + f"Invalid icon: {name}:{icon}. Icon name is not a existing enum value." + ) + + return [field, icon, self._get_display_icon(name, icon), enum_mapping[icon]] + + def _get_display_icon(self, name: str, icon: str) -> str: + return f'} "{name}:{icon}")' + + def _get_icon_path(self, property_name: str, value: str) -> str: + return f"{self._config.icon_path}/{property_name}_{value}.svg" diff --git a/scripts/hooks/generation/icons/icon_doc_options.py b/scripts/hooks/generation/icons/icon_doc_options.py new file mode 100644 index 0000000000000000000000000000000000000000..1bcbc5d7affcb2e8ce3731a234cbb7d23281beb2 --- /dev/null +++ b/scripts/hooks/generation/icons/icon_doc_options.py @@ -0,0 +1,8 @@ +from dataclasses import dataclass + + +@dataclass +class IconDocOptions: + schema: str + icon_path: str + external_property_page: str diff --git a/scripts/hooks/generation/icons/test_icon_doc_generator.py b/scripts/hooks/generation/icons/test_icon_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..b879cad688fa15d8dd5b0330a01b7355fd351008 --- /dev/null +++ b/scripts/hooks/generation/icons/test_icon_doc_generator.py @@ -0,0 +1,25 @@ +from .icon_doc_generator import IconDocGenerator +from .icon_doc_options import IconDocOptions + + +def test_icon_doc_generator(): + options = IconDocOptions("", "icons", "ifdo-core.json") + icon_doc_generator = IconDocGenerator(options) + schema = { + "type": "object", + "properties": { + "image-type": { + "type": "string", + "anyOf": [ + {"const": "still", "description": "Still image"}, + ], + } + }, + } + result = icon_doc_generator(schema, ["image-type_still.svg"]) + assert ( + result + == """| Field | Value | Icon | Description | +| ----- | ----- | ----- | ----- | +| [image-type](ifdo-core.json#image-type) | still |  | Still image |""" + ) diff --git a/scripts/hooks/generation/markdown_table.py b/scripts/hooks/generation/markdown_table.py new file mode 100644 index 0000000000000000000000000000000000000000..134b367e8e31eb9596c1c9277302ba7a8575fe1b --- /dev/null +++ b/scripts/hooks/generation/markdown_table.py @@ -0,0 +1,15 @@ +from typing import List + + +def generate_markdown_table(header: List[str], rows: List[List[str]]) -> str: + assert len(header) == len(rows[0]) + + header_row = _gen_markdown_table_row(header) + split_row = _gen_markdown_table_row(["-----" for _ in range(len(header))]) + table_rows = [_gen_markdown_table_row(row) for row in rows] + + return "\n".join([header_row] + [split_row] + table_rows) + + +def _gen_markdown_table_row(entries: List[str]): + return "|" + "|".join([f" {elem} " for elem in entries]) + "|" diff --git a/scripts/hooks/generation/schema/__init__.py b/scripts/hooks/generation/schema/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/scripts/hooks/generation/schema/requirement_table_generation.py b/scripts/hooks/generation/schema/requirement_table_generation.py new file mode 100644 index 0000000000000000000000000000000000000000..a6f2dfa0fc263c864ccc2a8bf204cd9df2535ab0 --- /dev/null +++ b/scripts/hooks/generation/schema/requirement_table_generation.py @@ -0,0 +1,40 @@ +from ..markdown_table import generate_markdown_table +from .requirement_table_generation_options import RequirementTableGenerationOptions + + +class RequirementTableGeneration: + def __init__(self, options: RequirementTableGenerationOptions): + self._options = options + + def __call__(self, struct_schema: dict, remote_schema: dict) -> str: + required_fields = self._get_required_fields(struct_schema) + table_header = ["Field", "Description"] + table_rows = [ + [ + f"[{field}]({self._options.path}#{field})", + f"{self._get_from_path(remote_schema, ["properties", field])["description"]}", + ] + for field in required_fields + ] + + return generate_markdown_table(table_header, table_rows) + + def _get_required_fields(self, schema: dict) -> list[str]: + path = self._options.schema_item.split("#")[1].split("/") + item = self._get_from_path(schema, path) + + return item["required"] + + @staticmethod + def _get_from_path(schema: dict, path: list) -> dict: + current = schema + for path in path: + if path == "": + continue + + if type(current) is list: + current = current[int(path)] + else: + current = current[path] + + return current diff --git a/scripts/hooks/generation/schema/requirement_table_generation_options.py b/scripts/hooks/generation/schema/requirement_table_generation_options.py new file mode 100644 index 0000000000000000000000000000000000000000..25c23d0777200f8dbdcaf016a2994d0e7bf34a84 --- /dev/null +++ b/scripts/hooks/generation/schema/requirement_table_generation_options.py @@ -0,0 +1,8 @@ +from dataclasses import dataclass + + +@dataclass +class RequirementTableGenerationOptions: + schema_item: str + remote_schema: str + path: str diff --git a/scripts/hooks/generation/schema/schema_doc_generator.py b/scripts/hooks/generation/schema/schema_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..19333ce2897fd926e8724e8d61dfb1d81fc114ca --- /dev/null +++ b/scripts/hooks/generation/schema/schema_doc_generator.py @@ -0,0 +1,215 @@ +from typing import Optional, List, Tuple + +import re + +from .schema_doc_options import SchemaDocOptions +from ..markdown_table import generate_markdown_table + + +class SchemaDocGenerator: + def __init__(self, config: SchemaDocOptions) -> None: + self._config = config + + def generate_schema_doc( + self, json_schema: dict, parents: Optional[list[str]] = None + ) -> str: + if parents is None: + parents = [] + + table = self.generate_property_table(json_schema, parents) + + if self._config.external_property_page != "": + return table + + properties = self._filter_lowest_properties(json_schema["properties"], parents) + property_docs = "\n".join( + [ + self._generate_property_doc(key, value, parents) + for key, value in properties.items() + if "$ref" not in value + ] + ) + return table + "\n" + property_docs + + def generate_property_table( + self, schema_object: dict, parents: Optional[list[str]] = None + ) -> str: + properties = self._filter_lowest_properties( + schema_object["properties"], parents + ) + + table_header = ["Field", "Type", "Description"] + + table_rows = [ + [ + f"[{key}]({self._config.external_property_page}#{self._generate_property_link(parents + [key])})", + value["type"], + value["description"], + ] + for key, value in properties.items() + if "$ref" not in value + ] + + if self._config.display_required and len(parents) > 0: + table_header += ["Required"] + table_rows = [ + row + ["✔" if key in schema_object.get("required", []) else ""] + for key, row in zip( + (key for key, value in properties.items() if "$ref" not in value), + table_rows, + ) + ] + + return generate_markdown_table(table_header, table_rows) + + def _filter_lowest_properties(self, properties: dict, parents: List[str]) -> dict: + if len(parents) > 0: + return properties + + return self._filter_properties(properties, self._config.property_filter) + + @staticmethod + def _filter_properties( + properties: dict, property_filter: Optional[str] = None + ) -> dict: + if property_filter is None: + return properties + return { + key: value + for key, value in properties.items() + if re.match(property_filter, key) is not None + } + + @staticmethod + def _generate_property_link(path: List[str]): + return "-".join(path).lower() + + def _generate_property_doc( + self, name: str, property: dict, parents: list[str] + ) -> str: + properties_type = property["type"] + + title = f'{"#" * (len(parents) + 3)} {self._gen_breadcrumbs(parents, name)}' + lines: List[Tuple[str, str]] = [("Type", properties_type)] + + if ( + properties_type == "string" + and "anyOf" in property + and {} not in property["anyOf"] + ): + lines.append( + ("Must be one of", "\n\n" + self._generate_enum_doc(property) + "\n\n") + ) + + elif properties_type == "array": + lines += self._generate_array_doc(property) + + elif properties_type == "number" or properties_type == "integer": + lines.append(("Limits", self._generate_number_doc(property))) + + lines.append(("Description", f'\n> {property["description"]}\n\n')) + + if properties_type == "array": + if self._has_local_reference(property["items"]): + lines.append( + ( + "Item Properties", + self._gen_reference_link(property["items"]["$ref"]), + ) + ) + elif property["items"]["type"] == "object": + lines.append( + ( + "Item Properties", + "\n\n" + + self.generate_schema_doc(property["items"], parents + [name]), + ) + ) + + if properties_type == "object" and "properties" in property: + lines.append( + ( + "Properties", + "\n\n" + self.generate_schema_doc(property, parents + [name]), + ) + ) + + output = ( + "\n" + + title + + "\n" + + "<br>\n".join([f"***{tag}***: {row}" for tag, row in lines]) + + "\n\n" + ) + + return output + + @staticmethod + def _gen_breadcrumbs(parents: List[str], child: str) -> str: + return " > ".join( + [ + f"[{parent}](#{"-".join(parents[:i+1])})" + for i, parent in enumerate(parents) + ] + + [child] + ) + + @staticmethod + def _has_local_reference(property: dict) -> bool: + if "$ref" not in property: + return False + + path = property["$ref"].split("/") + return path[0] == "#" and path[1] == "properties" + + @staticmethod + def _gen_reference_link(reference: str) -> str: + path = reference.split("/") + filtered_path = [p for p in path[1:] if p not in ["properties", "items"]] + return f'[{" > ".join(filtered_path)}](#{"-".join(filtered_path)})' + + @staticmethod + def _generate_enum_doc(property: dict) -> str: + table_header = ["Value", "Description"] + table_rows = [ + [entry["const"], entry["description"]] for entry in property["anyOf"] + ] + return generate_markdown_table(table_header, table_rows) + + @staticmethod + def _generate_number_doc(property: dict) -> str: + minimum_string = "(-∞" + if "minimum" in property: + minimum_string = f"[{property['minimum']}" + elif "exclusiveMinimum" in property: + minimum_string = f"({property['exclusiveMinimum']}" + + maximum_string = "∞)" + if "maximum" in property: + maximum_string = f"{property['maximum']}]" + elif "exclusiveMaximum" in property: + maximum_string = f"{property['exclusiveMaximum']})" + + return f"{minimum_string}, {maximum_string}" + + @staticmethod + def _generate_array_doc(property: dict) -> List[Tuple[str, str]]: + lines = [] + if "minItems" in property: + lines.append(("Min Items", property["minItems"])) + if "maxItems" in property: + lines.append(("Max Items", property["maxItems"])) + if "items" in property and "type" in property["items"]: + lines.append(("Item Type", property["items"]["type"])) + if ( + property["items"]["type"] == "number" + or property["items"]["type"] == "integer" + ): + lines.append( + ( + "Item Limits", + SchemaDocGenerator._generate_number_doc(property["items"]), + ) + ) + + return lines diff --git a/scripts/hooks/generation/schema/schema_doc_options.py b/scripts/hooks/generation/schema/schema_doc_options.py new file mode 100644 index 0000000000000000000000000000000000000000..2559b6d367cd1dd55e45c2c6e6c3faa04f4741d6 --- /dev/null +++ b/scripts/hooks/generation/schema/schema_doc_options.py @@ -0,0 +1,10 @@ +from dataclasses import dataclass +from typing import Optional + + +@dataclass +class SchemaDocOptions: + schema: str + property_filter: Optional[str] = None + display_required: bool = False + external_property_page: str = "" diff --git a/scripts/hooks/generation/schema/schema_references_resolver.py b/scripts/hooks/generation/schema/schema_references_resolver.py new file mode 100644 index 0000000000000000000000000000000000000000..3c92be26d18b142d8f08bd120458b912f78c7815 --- /dev/null +++ b/scripts/hooks/generation/schema/schema_references_resolver.py @@ -0,0 +1,105 @@ +import json +from copy import copy +from typing import Optional, List, Tuple + + +class SchemaReferencesResolver: + """ + Resolves $refs inside a json schema. + If the same definition is referenced multiple times, only the first (lowest) occurrence is completely resolved, + while the other will reference the first occurrence. + """ + + def __init__(self, non_local_refs: Optional[dict] = None): + if non_local_refs is None: + self.non_local_refs = {} + else: + self._non_local_refs = non_local_refs + + @classmethod + def from_reference_table(cls, table: List[Tuple[str, str]]): + refs = {row[0]: cls._load_json(row[1]) for row in table} + return cls(refs) + + @staticmethod + def _load_json(filepath: str) -> dict: + with open(filepath, "r") as json_file: + return json.load(json_file) + + def __call__(self, root: dict): + todo = [[key] for key in root.keys()] + reference_cache = {} + while len(todo) > 0: + current_path = todo.pop(0) + if current_path[0] == "$defs": + continue + + sub_schema = self._resolve_path(root, current_path) + + if type(sub_schema) is not dict: + continue + + if "$ref" in sub_schema: + self._handle_reference(root, sub_schema, current_path, reference_cache) + + todo += [current_path + [key] for key in sub_schema.keys()] + + return root + + @staticmethod + def _resolve_path(root: dict, path: List[str]) -> dict: + current = root + for p in path: + current = current[p] + + return current + + def _handle_reference( + self, root: dict, sub_schema: dict, current_path: str, reference_cache: dict + ) -> None: + if sub_schema["$ref"] in reference_cache: + sub_schema["$ref"] = reference_cache[sub_schema["$ref"]] + return + + ref = self._resolve_reference(root, sub_schema["$ref"]) + if ref is None: + return + + reference_cache[sub_schema["$ref"]] = "#/" + "/".join(current_path) + del sub_schema["$ref"] + + sub_schema.update(ref) + + def _resolve_reference(self, schema_root: dict, reference: str) -> Optional[dict]: + if reference[0] == "#": + return self._resolve_local_reference(schema_root, reference) + + if reference in self._non_local_refs: + resolved = copy(self._non_local_refs[reference]) + self._pull_defs_into_root(schema_root, resolved) + return resolved + + return None + + @staticmethod + def _pull_defs_into_root(schema_root: dict, resolved_reference: dict) -> None: + if "$defs" not in resolved_reference: + return + + if "$defs" in schema_root: + schema_root["$defs"].update(resolved_reference["$defs"]) + else: + schema_root["$defs"] = resolved_reference["$defs"] + + del resolved_reference["$defs"] + + @staticmethod + def _resolve_local_reference(schema_root: dict, reference: str) -> Optional[dict]: + path = reference.split("/") + path = path[1:] + + current = schema_root + for p in path: + current = current[p] + + return current diff --git a/scripts/hooks/generation/schema/test_requirement_table_generation.py b/scripts/hooks/generation/schema/test_requirement_table_generation.py new file mode 100644 index 0000000000000000000000000000000000000000..c284305e9022ae8e8324207d14f14fe0d991f589 --- /dev/null +++ b/scripts/hooks/generation/schema/test_requirement_table_generation.py @@ -0,0 +1,22 @@ +from .requirement_table_generation import RequirementTableGeneration +from .requirement_table_generation_options import RequirementTableGenerationOptions + + +def test_requirement_table_generation(): + schema = {"type": "object", "properties": {}, "required": ["image-name"]} + + reference_schema = { + "type": "object", + "properties": {"image-name": {"type": "string", "description": "Image name"}}, + } + + options = RequirementTableGenerationOptions("schema.json#/", "", "path/") + + result = RequirementTableGeneration(options)(schema, reference_schema) + + assert ( + result + == """| Field | Description | +| ----- | ----- | +| [image-name](path/#image-name) | Image name |""" + ) diff --git a/scripts/hooks/generation/schema/test_schema_doc_generator.py b/scripts/hooks/generation/schema/test_schema_doc_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..e32f57437c4261f26723746ee8405b4ac8d31aae --- /dev/null +++ b/scripts/hooks/generation/schema/test_schema_doc_generator.py @@ -0,0 +1,93 @@ +from .schema_doc_generator import SchemaDocGenerator +from .schema_doc_options import SchemaDocOptions + + +def test_generate_schema_doc(): + schema = { + "type": "object", + "properties": { + "image-name": {"type": "string", "description": "Image name"}, + }, + } + + doc = SchemaDocGenerator( + SchemaDocOptions("", display_required=True) + ).generate_schema_doc(schema) + assert ( + doc + == """| Field | Type | Description | +| ----- | ----- | ----- | +| [image-name](#image-name) | string | Image name | + +### image-name +***Type***: string<br> +***Description***: +> Image name + + + +""" + ) + + +def test_filter_properties(): + properties = {"image-set-name": {}, "image-name": {}} + + output = SchemaDocGenerator._filter_properties(properties, r"image-(?!.*set).*") + assert output == {"image-name": {}} + + +def test_gen_reference_link(): + reference = "#/properties/image-pixels/items/properties/depth" + assert ( + SchemaDocGenerator._gen_reference_link(reference) + == "[image-pixels > depth](#image-pixels-depth)" + ) + + +def test_generate_enum_doc(): + property = { + "type": "string", + "anyOf": [ + {"const": "slide", "description": "bla"}, + ], + } + output = SchemaDocGenerator._generate_enum_doc(property) + assert ( + output + == """| Value | Description | +| ----- | ----- | +| slide | bla |""" + ) + + +def test_generate_number_doc_no_limits(): + property = {} + assert SchemaDocGenerator._generate_number_doc(property) == "(-∞, ∞)" + + +def test_generate_number_doc_limits(): + property = {"minimum": 0, "maximum": 1} + assert SchemaDocGenerator._generate_number_doc(property) == "[0, 1]" + + +def test_generate_number_doc_exclusive_limits(): + property = {"exclusiveMinimum": 0, "exclusiveMaximum": 1} + assert SchemaDocGenerator._generate_number_doc(property) == "(0, 1)" + + +def test_generate_array_doc(): + property = { + "minItems": 1, + "maxItems": 3, + "items": { + "type": "number", + }, + } + output = SchemaDocGenerator._generate_array_doc(property) + assert output == [ + ("Min Items", 1), + ("Max Items", 3), + ("Item Type", "number"), + ("Item Limits", "(-∞, ∞)"), + ] diff --git a/scripts/hooks/generation/schema/test_schema_resolver.py b/scripts/hooks/generation/schema/test_schema_resolver.py new file mode 100644 index 0000000000000000000000000000000000000000..a4a84c57af7160a932d8fb6df85c1bfe8aba2727 --- /dev/null +++ b/scripts/hooks/generation/schema/test_schema_resolver.py @@ -0,0 +1,110 @@ +import pytest +from .schema_references_resolver import SchemaReferencesResolver + + +@pytest.fixture() +def non_local_references(): + return [ + ( + "https://marine-imaging.com/fair/schemas/provenance.json", + "standard/schema/provenance.json", + ), + ( + "https://marine-imaging.com/fair/schemas/annotation.json", + "standard/schema/annotation.json", + ), + ] + + +def test_local_reference(): + schema = { + "type": "object", + "properties": {"image-name": {"$ref": "#/$defs/image-name"}}, + "$defs": {"image-name": {"type": "string"}}, + } + + resolved_schema = SchemaReferencesResolver()(schema) + assert resolved_schema["properties"]["image-name"]["type"] == "string" + + +def test_reference_cache(): + schema = { + "type": "object", + "properties": { + "image-name": {"$ref": "#/$defs/image-name"}, + "image-prop": {"$ref": "#/$defs/image-prop"}, + }, + "$defs": { + "image-name": {"type": "string"}, + "image-prop": { + "type": "object", + "properties": {"image-name": {"$ref": "#/$defs/image-name"}}, + }, + }, + } + resolved_schema = SchemaReferencesResolver()(schema) + assert resolved_schema["properties"]["image-name"]["type"] == "string" + assert ( + resolved_schema["properties"]["image-prop"]["properties"]["image-name"]["$ref"] + == "#/properties/image-name" + ) + + +def test_reference_lowest_reference(): + schema = { + "type": "object", + "properties": { + "image-prop": {"$ref": "#/$defs/image-prop"}, + "image-name": {"$ref": "#/$defs/image-name"}, + }, + "$defs": { + "image-name": {"type": "string"}, + "image-prop": { + "type": "object", + "properties": {"image-name": {"$ref": "#/$defs/image-name"}}, + }, + }, + } + resolved_schema = SchemaReferencesResolver()(schema) + assert resolved_schema["properties"]["image-name"]["type"] == "string" + assert ( + resolved_schema["properties"]["image-prop"]["properties"]["image-name"]["$ref"] + == "#/properties/image-name" + ) + + +def test_non_local_reference(non_local_references): + schema = { + "type": "object", + "properties": { + "provenance": { + "$ref": "https://marine-imaging.com/fair/schemas/provenance.json" + } + }, + } + + resolved_schema = SchemaReferencesResolver.from_reference_table( + non_local_references + )(schema) + assert ( + resolved_schema["properties"]["provenance"]["properties"]["provenance-agents"][ + "type" + ] + == "array" + ) + + +def test_pull_defs_into_root_no_merge(): + schema = {"type": "object", "properties": {"image-name": {}}, "$defs": {}} + + resolved_schema = {} + SchemaReferencesResolver()._pull_defs_into_root(schema, resolved_schema) + assert len(list(schema["$defs"].keys())) == 0 + + +def test_pull_defs_into_root_merge(): + schema = {"type": "object", "properties": {"image-name": {}}, "$defs": {}} + + resolved_schema = {"$defs": {"image-name": {"type": "string"}}} + SchemaReferencesResolver()._pull_defs_into_root(schema, resolved_schema) + assert schema["$defs"]["image-name"]["type"] == "string" diff --git a/scripts/hooks/generation/test_markdown_table.py b/scripts/hooks/generation/test_markdown_table.py new file mode 100644 index 0000000000000000000000000000000000000000..74fd57901d85908ed5ced44034f7dc7c9a68964e --- /dev/null +++ b/scripts/hooks/generation/test_markdown_table.py @@ -0,0 +1,11 @@ +from .markdown_table import generate_markdown_table + + +def test_generate_markdown_table(): + table = generate_markdown_table(["Column"], [["Entry"]]) + assert ( + table + == """| Column | +| ----- | +| Entry |""" + ) diff --git a/scripts/hooks/load_standard_files.py b/scripts/hooks/load_standard_files.py new file mode 100644 index 0000000000000000000000000000000000000000..23f2c048d39f39b3f490fc7c61a6dceb2318fe8a --- /dev/null +++ b/scripts/hooks/load_standard_files.py @@ -0,0 +1,78 @@ +import glob +import os +from io import BytesIO + +from git import Repo +from git import Tag +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import Files, File + +OMIT_LATEST = os.environ.get("PROD_ENV") == "1" + + +def on_files(files: Files, config: MkDocsConfig) -> Files: + if not OMIT_LATEST: + files = _insert_latest_standard_folder(files, config) + + files = _insert_tags_standard_folders(files, config) + return files + + +def _insert_latest_standard_folder(files: Files, config: MkDocsConfig) -> Files: + for file in glob.glob("standard/**/*.*", recursive=True): + files.append( + File.generated( + src_uri=_restructure_latest_standard_path(file), + abs_src_path=file, + config=config, + ) + ) + + return files + + +def _restructure_latest_standard_path(path: str) -> str: + norm_path = os.path.normpath(path) + split_path = norm_path.split(os.path.sep) + new_part_path = [split_path[0]] + ["latest"] + split_path[1:] + new_path = str(os.path.join(*new_part_path)) + return new_path + + +def _insert_tags_standard_folders(files: Files, config: MkDocsConfig) -> Files: + repo = Repo(".") + for tag in repo.tags: + files = _insert_single_tag_standard_folder(tag, files, config) + + return files + + +def _insert_single_tag_standard_folder( + tag: Tag, files: Files, config: MkDocsConfig +) -> Files: + version = tag.tag.tag + + todo = [([version], tag.commit.tree["standard"])] + tag_standard_blobs = [] + while len(todo) > 0: + current_path, current_dir = todo.pop() + for entry in current_dir: + if entry.type == "tree": + todo.append((current_path + [entry.name], entry)) + elif entry.type == "blob": + tag_standard_blobs.append((current_path + [entry.name], entry)) + else: + raise Exception("Unknown type: " + entry.type) + + for path, blob in tag_standard_blobs: + buffer = BytesIO() + blob.stream_data(buffer) + buffer.seek(0) + content = buffer.read().decode("utf-8") + files.append( + File.generated( + src_uri="/".join(["standard"] + path), content=content, config=config + ) + ) + + return files diff --git a/scripts/hooks/process_nav_template.py b/scripts/hooks/process_nav_template.py new file mode 100644 index 0000000000000000000000000000000000000000..8c060bed7c5611a9bda61d72257dfae58b5adc96 --- /dev/null +++ b/scripts/hooks/process_nav_template.py @@ -0,0 +1,76 @@ +import os +from copy import deepcopy +from typing import List, Tuple + +from git import Repo +from mkdocs.config.defaults import MkDocsConfig +from mkdocs.structure.files import Files + +OMIT_LATEST = os.environ.get("PROD_ENV") == "1" +SECTION_VERSION_TEMPLATE_STRING = "{version}" + + +def on_files(files: Files, config: MkDocsConfig) -> Files: + _process_nav_templates(config) + return files + + +def _process_nav_templates(config: MkDocsConfig) -> None: + repo = Repo(".") + versions = [str(tag.tag.tag) for tag in repo.tags] + + if not OMIT_LATEST: + versions += ["latest"] + + todo = [config["nav"]] + while len(todo) > 0: + current = todo.pop() + todo += [ + _get_section_entry(elem)[1] + for elem in current + if type(_get_section_entry(elem)[1]) is list + and _get_section_entry(elem)[0] != SECTION_VERSION_TEMPLATE_STRING + ] + _process_sections(current, versions) + + +def _process_sections(current: List[dict], versions: list[str]) -> None: + template_section_indices = [ + i + for i, elem in enumerate(current) + if type(_get_section_entry(elem)[1]) is list + and _get_section_entry(elem)[0] == SECTION_VERSION_TEMPLATE_STRING + ] + for i in template_section_indices: + entry_name, entry = _get_section_entry(current[i]) + sections = _process_versions_nav_template(entry, versions) + current += sections + current.pop(i) + + +def _get_section_entry(entry_elem: dict) -> Tuple[str, list | str]: + entry_name = list(entry_elem.keys())[0] + entry = entry_elem[entry_name] + return entry_name, entry + + +def _process_versions_nav_template( + section: list, versions: List[str] +) -> List[dict[str, list]]: + return [ + {version: _process_version_nav_template(deepcopy(section), version)} + for version in versions + ] + + +def _process_version_nav_template(section: list, version: str) -> list: + for current in section: + entry_name = list(current.keys())[0] + entry = current[entry_name] + if type(entry) is list: + _process_version_nav_template(entry, version) + + if type(entry) is str: + current[entry_name] = current[entry_name].format(version=version) + + return section diff --git a/scripts/test_schema.py b/scripts/test_schema.py new file mode 100644 index 0000000000000000000000000000000000000000..9d050eb2f1b9d5ac44ea17975f5c253e2b74afdc --- /dev/null +++ b/scripts/test_schema.py @@ -0,0 +1,49 @@ +import json +import sys + +from jsonschema import Draft202012Validator +from referencing import Registry, Resource + + +def test_example(example_file: str): + schema = load_json("standard/schema/ifdo.json") + example = load_json(example_file) + + registry = Registry().with_resources( + [ + ( + "https://marine-imaging.com/fair/schemas/ifdo-core.json", + Resource.from_contents(load_json("standard/schema/ifdo-core.json")), + ), + ( + "https://marine-imaging.com/fair/schemas/ifdo-capture.json", + Resource.from_contents(load_json("standard/schema/ifdo-capture.json")), + ), + ( + "https://marine-imaging.com/fair/schemas/ifdo-content.json", + Resource.from_contents(load_json("standard/schema/ifdo-content.json")), + ), + ( + "https://marine-imaging.com/fair/schemas/provenance.json", + Resource.from_contents(load_json("standard/schema/provenance.json")), + ), + ( + "https://marine-imaging.com/fair/schemas/annotation.json", + Resource.from_contents(load_json("standard/schema/annotation.json")), + ), + ] + ) + validator = Draft202012Validator(schema, registry=registry) + validator.validate(example) + + +def load_json(filepath: str) -> dict: + with open(filepath, "r") as file: + return json.load(file) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + raise Exception("Please provide an example file") + + test_example(sys.argv[1]) diff --git a/standard/changelog.md b/standard/changelog.md new file mode 100644 index 0000000000000000000000000000000000000000..fe70e7f56ed7a9a550ea04dab4faf5565f5d825f --- /dev/null +++ b/standard/changelog.md @@ -0,0 +1,5 @@ +# Changelog + +```git-tag-changelog + +``` \ No newline at end of file diff --git a/standard/documentation/iFDO-capture.md b/standard/documentation/iFDO-capture.md new file mode 100644 index 0000000000000000000000000000000000000000..e33a2e76d2a5a0fd0de7566ce93fbbd1ece9eb27 --- /dev/null +++ b/standard/documentation/iFDO-capture.md @@ -0,0 +1,6 @@ +# iFDO capture fields + +```json-schema-gen +schema: ../schema/ifdo-capture.json +display_required: True +``` \ No newline at end of file diff --git a/standard/documentation/iFDO-content.md b/standard/documentation/iFDO-content.md new file mode 100644 index 0000000000000000000000000000000000000000..5e9c6660ad46b03e2bcf93f328a17359274ef570 --- /dev/null +++ b/standard/documentation/iFDO-content.md @@ -0,0 +1,14 @@ +# iFDO content fields + +## Domain-specific iFDO content fields + +```json-schema-gen +schema: ../schema/ifdo-content.json +display_required: True +``` + +## iFDO content fields for annotations +```json-schema-gen +schema: ../schema/annotation.json +display_required: True +``` diff --git a/standard/documentation/iFDO-core.md b/standard/documentation/iFDO-core.md new file mode 100644 index 0000000000000000000000000000000000000000..7ca2b73c87edd6e11276cbe92b84282f98884426 --- /dev/null +++ b/standard/documentation/iFDO-core.md @@ -0,0 +1,17 @@ +# iFDO core fields + +## Header information in the `image-set-header` part + +```json-schema-gen +schema: ../schema/ifdo-core.json +property_filter: image-set-.* +display_required: True +``` + +## Image item information + +```json-schema-gen +schema: ../schema/ifdo-core.json +property_filter: image-(?!.*set).* +display_required: True +``` diff --git a/standard/documentation/iFDO-structure.md b/standard/documentation/iFDO-structure.md new file mode 100644 index 0000000000000000000000000000000000000000..e0446638fcad86a89a48aa44cc2a622bf7205165 --- /dev/null +++ b/standard/documentation/iFDO-structure.md @@ -0,0 +1,49 @@ +# iFDO Structure +An iFDO file is split into two parts: An image set header containing information about the image set and default values +for the image set, and an image set items `object` describing each image item in the image set. + +## Image Set Header +The `image-set-header` is an `object`, which can contain any field defined by [iFDO Core](./iFDO-core.md), [iFDO Capture](./iFDO-capture.md) and [iFDO Content](./iFDO-content.md) as default values for the hole image set. +The following list provides an overview of the required fields, which are necessary to ensure the FAIRness of the iFDO file. +### Required Fields +```json-link-req-gen +schema_item: ../schema/ifdo.json#/properties/image-set-header/ +remote_schema: ../schema/ifdo-core.json +path: iFDO-core.md +``` + +## Image Set Items +The `image-set-items` `object` maps the filenames of the image items of the image set to their information. The information +is given either as an [Image Item](#image-item) if the item is a still image or [Video Item](#video-item) if the item is a video. + +### Image Item +The image item `object` contains the information for a still image and can contain any field defined by [iFDO Core](./iFDO-core.md), [iFDO Capture](./iFDO-capture.md) and [iFDO Content](./iFDO-content.md) as default values for the hole image set. +To uniquely identify the image by other means then the file name the following fields must be provided. +#### Required Fields +```json-link-req-gen +schema_item: ../schema/ifdo.json#/$defs/image-item-core +remote_schema: ../schema/ifdo-core.json +path: iFDO-core.md +``` + +### Video Item +The video item `array` allows to specify information for the hole video file in its first entry, the [Video Header](#video-header) and information which changes over time in the following entries using the [Video Frames](#video-frames). +#### Video Header +The video header `object` is structurally identical to the [Image Item](#image-item), but functionally also provides default values for the rest of the [Video Frames](#video-frames). +##### Required Fields +```json-link-req-gen +schema_item: ../schema/ifdo.json#/$defs/image-item-core +remote_schema: ../schema/ifdo-core.json +path: iFDO-core.md +``` + +#### Video Frames +The video frame `object` can be used to specify information varying over the duration of the video. It can contain +any field defined by [iFDO Core](./iFDO-core.md), [iFDO Capture](./iFDO-capture.md) and [iFDO Content](./iFDO-content.md). + +##### Required Fields +```json-link-req-gen +schema_item: ../schema/ifdo.json#/properties/image-set-items/additionalProperties/oneOf/1/items +remote_schema: ../schema/ifdo-core.json +path: iFDO-core.md +``` diff --git a/standard/documentation/iFDO_vocabulary-term-mapping.md b/standard/documentation/iFDO_vocabulary-term-mapping.md new file mode 100644 index 0000000000000000000000000000000000000000..9dbe106c65a6bd8e68612e4d441e25daf60a85a2 --- /dev/null +++ b/standard/documentation/iFDO_vocabulary-term-mapping.md @@ -0,0 +1,29 @@ +# Mapping iFDO fields to other standards +Fields of the [iFDO](../../../overview/iFDO-overview.md) image metadata standard are inspired by other metadata standards. iFDOs are +designed to facilitate mapping between all relevant image metadata standards. Below, you can find a mapping between +the iFDO fields and the corresponding field names (aka terms) in other metadata schemas. The iFDO JSON schema file +implements this mapping in a machine-readable fashion. + +## iFDO Core + +```json-schema-context-gen +schema: ../schema/ifdo-core.json +``` + +## iFDO Capture + +```json-schema-context-gen +schema: ../schema/ifdo-capture.json +``` + +## iFOD Content + +```json-schema-context-gen +schema: ../schema/ifdo-content.json +``` + + +## Disclaimer +Vocabularies, repositories or other sources that do not enforce structured metadata or data (like Zenodo or DRYAD) +are not considered here as they do not lead to FAIRness of data. Similarly, all projects, workflows, etc. that rely +on these sources are omitted as well. diff --git a/standard/examples/ifdo-image-example.json b/standard/examples/ifdo-image-example.json new file mode 100644 index 0000000000000000000000000000000000000000..b7993fbf9c26aca11615743034432510926b1214 --- /dev/null +++ b/standard/examples/ifdo-image-example.json @@ -0,0 +1,135 @@ +{ + "$schema": "https://marine-imaging.com/fair/schemas/ifdo-v2.0.0.json", + "image-set-header": { + "image-set-ifdo-version": "v2.0.0", + "image-set-name": "SO268 SO268-1_21-1_OFOS SO_CAM-1_Photo_OFOS", + "image-set-uuid": "f840644a-fe4a-46a7-9791-e32c211bcbf5", + "image-set-handle": "https://hdl.handle.net/20.500.12085/f840644a-fe4a-46a7-9791-e32c211bcbf5", + "image-abstract": "Acquired by camera SO_CAM-1_Photo_OFOS mounted on platform SO_PFM-01_OFOS during project SO268 (event: SO268-1_21-1_OFOS). Navigation data were automatically edited by the MarIQT software (removal of outliers, smoothed and splined to fill time gaps) and linked to the image data by timestamp.", + "image-copyright": "(c) GEOMAR Helmholtz Centre for Ocean Research Kiel. Contact: presse@geomar.de", + "image-license": { + "name": "CC-BY", + "uri": "https://creativecommons.org/licenses/by/4.0/legalcode" + }, + "image-context": { + "name": "Mining Impact of the Joint Programming Initiative of Healthy and Productive Seas and Oceans (JPIOceans)", + "uri": "https://miningimpact.geomar.de/de/miningimpact-2" + }, + "image-project": { + "name": "SO268", + "uri": "https://doi.org/10.3289/GEOMAR_REP_NS_59_20" + }, + "image-event": { + "name": "SO268-1_21-1_OFOS", + "uri": "https://portal.geomar.de/metadata/event/show/1603320?leg=348623" + }, + "image-platform": { + "name": "SO_PFM-01_OFOS", + "uri": "https://dm.pages.geomar.de/equipment/equipment/SO/PFM/SO_PFM-1_OFOS_Isitec/" + }, + "image-sensor": { + "name": "SO_CAM-1_Photo_OFOS", + "uri": "https://dm.pages.geomar.de/equipment/equipment/SO/CAM/SO_CAM-1_Photo_OFOS/" + }, + "image-pi": { + "name": "Timm Schoening", + "uri":"https://orcid.org/0000-0002-0035-3282" + }, + "image-creators": [ + { + "name": "Yasemin Bodur", + "uri": "https://orcid.org/0000-0001-8758-8617" + }, + { + "name": "Timm Schoening", + "uri": "https://orcid.org/0000-0002-0035-3282" + } + ], + "image-objective": "Baseline imaging in nodule mining and reference areas. Some pre-/post-impact disturbance mapping", + "image-spatial-constraints": "Poly-metallic nodule areas in the Pacific Ocean", + "image-spectral-resolution": "rgb", + "image-target-environment": "Deep-sea floor, abyssal plains.", + "image-temporal-constraints": "No specific temporal constraints, some pre-/post-impact disturbance mapping for a dredge experiment", + "image-time-synchronisation": "Manual check and setting of the OFOS cameras to the correct UTC before the deployment", + "image-acquisition": "photo", + "image-capture-mode": "mixed", + "image-coordinate-uncertainty-meters": 4.74, + "image-coordinate-reference-system": "EPSG:4326", + "image-curation-protocol": "See provenance files for events", + "image-deployment": "survey", + "image-illumination": "artificial light", + "image-item-identification-scheme": "EVENT_SENSOR_DATE_TIME.jpg", + "image-marine-zone": "seafloor", + "image-navigation": "beacon", + "image-quality": "raw", + "image-pixel-magnitude": "mm", + "image-scale-reference": "laser marker", + "image-datetime": "2019-03-04 08:37:24.000000", + "image-latitude": 11.9294422, + "image-longitude": -117.0407515, + "image-altitude-meters": -4094.5, + "image-annotation-creators": [ + { + "id": "https://orcid.org/0009-0001-1994-0399", + "name": "Christopher Krämmer" + } + ], + "image-annotation-labels": [ + { + "id": "urn:lsid:marinespecies.org:taxname:281088", + "name": "Hoplosebastes armatus Schmidt,1929" + } + ] + }, + "image-set-items": { + "SO268-1_21-1_OFOS_SO_CAM-1_20190304_083724.JPG": { + "image-handle": "", + "image-area-square-meters": 21.6994, + "image-average-color": [168, 187, 144], + "image-datetime": "2019-03-04 08:37:24.000000", + "image-altitude-meters": -4094.5, + "image-entropy": 0.8174957092476102, + "image-hash-sha256": "83f30eb35d1325c44c85fba0cf478825c0a629d20177a945069934f6cd07e087", + "image-latitude": 11.9294422, + "image-longitude": -117.0407515, + "image-mpeg7-colorstatistic": [27.0, 255.0, 38.0, 255.0, 36.0, 255.0, 169.3751983642578, 211.97219848632812, 198.2913360595703, 25.55811309814453, 31.31110954284668, 37.18994140625, 177.0, 224.0, 212.0, 0.8022223711013794, 0.806853175163269, 0.8450505137443542], + "image-uuid": "c6b8d981-05c7-449f-85a9-906ab866bfb6", + "image-annotations": [ + { + "shape": "rectangle", + "coordinates": [ + [ + 2274.28, + 1766.4, + 2299.44, + 1767.76, + 2297.96, + 1795.1, + 2272.8, + 1793.74 + ] + ], + "labels": [ + { + "label": "urn:lsid:marinespecies.org:taxname:281088", + "annotator": "https://orcid.org/0009-0001-1994-0399", + "created-at": "2024-11-22T06:03:56.655940+01:00" + } + ] + } + ] + }, + "SO268-1_21-1_OFOS_SO_CAM-1_20190304_083734.JPG": { + "image-handle": "", + "image-area-square-meters": 29.6263, + "image-average-color": [116, 141, 114], + "image-datetime": "2019-03-04 08:37:34.000000", + "image-altitude-meters": -4094.6, + "image-entropy": 0.8340960692175852, + "image-hash-sha256": "819e1810dccd9025310d7841a994b94bcdc438ae74ec5095ce01f1bd46143c4e", + "image-latitude": 11.9294418, + "image-longitude": -117.040753, + "image-uuid": "daad4a74-5c16-49d0-9775-efa67f0459f4" + } + } +} \ No newline at end of file diff --git a/standard/examples/ifdo-video-example.json b/standard/examples/ifdo-video-example.json new file mode 100644 index 0000000000000000000000000000000000000000..3f354f5db215099241cf5952600643cd65a6af7d --- /dev/null +++ b/standard/examples/ifdo-video-example.json @@ -0,0 +1,111 @@ +{ + "$schema": "https://marine-imaging.com/fair/schemas/ifdo-v2.0.0.json", + "image-set-header": { + "image-set-ifdo-version": "v2.0.0", + "image-set-name": "SO268 SO268-1_21-1_OFOS SO_CAM-1_Photo_OFOS", + "image-set-uuid": "f840644a-fe4a-46a7-9791-e32c211bcbf5", + "image-set-handle": "https://hdl.handle.net/20.500.12085/f840644a-fe4a-46a7-9791-e32c211bcbf5", + "image-abstract": "Acquired by camera SO_CAM-1_Photo_OFOS mounted on platform SO_PFM-01_OFOS during project SO268 (event: SO268-1_21-1_OFOS). Navigation data were automatically edited by the MarIQT software (removal of outliers, smoothed and splined to fill time gaps) and linked to the image data by timestamp.", + "image-copyright": "(c) GEOMAR Helmholtz Centre for Ocean Research Kiel. Contact: presse@geomar.de", + "image-license": { + "name": "CC-BY", + "uri": "https://creativecommons.org/licenses/by/4.0/legalcode" + }, + "image-context": { + "name": "Mining Impact of the Joint Programming Initiative of Healthy and Productive Seas and Oceans (JPIOceans)", + "uri": "https://miningimpact.geomar.de/de/miningimpact-2" + }, + "image-project": { + "name": "SO268", + "uri": "https://doi.org/10.3289/GEOMAR_REP_NS_59_20" + }, + "image-event": { + "name": "SO268-1_21-1_OFOS", + "uri": "https://portal.geomar.de/metadata/event/show/1603320?leg=348623" + }, + "image-platform": { + "name": "SO_PFM-01_OFOS", + "uri": "https://dm.pages.geomar.de/equipment/equipment/SO/PFM/SO_PFM-1_OFOS_Isitec/" + }, + "image-sensor": { + "name": "SO_CAM-1_Photo_OFOS", + "uri": "https://dm.pages.geomar.de/equipment/equipment/SO/CAM/SO_CAM-1_Photo_OFOS/" + }, + "image-pi": { + "name": "Timm Schoening", + "uri":"https://orcid.org/0000-0002-0035-3282" + }, + "image-creators": [ + { + "name": "Yasemin Bodur", + "uri": "https://orcid.org/0000-0001-8758-8617" + }, + { + "name": "Timm Schoening", + "uri": "https://orcid.org/0000-0002-0035-3282" + } + ], + "image-objective": "Baseline imaging in nodule mining and reference areas. Some pre-/post-impact disturbance mapping", + "image-spatial-constraints": "Poly-metallic nodule areas in the Pacific Ocean", + "image-spectral-resolution": "rgb", + "image-target-environment": "Deep-sea floor, abyssal plains.", + "image-temporal-constraints": "No specific temporal constraints, some pre-/post-impact disturbance mapping for a dredge experiment", + "image-time-synchronisation": "Manual check and setting of the OFOS cameras to the correct UTC before the deployment", + "image-acquisition": "photo", + "image-capture-mode": "mixed", + "image-coordinate-uncertainty-meters": 4.74, + "image-coordinate-reference-system": "EPSG:4326", + "image-curation-protocol": "See provenance files for events", + "image-deployment": "survey", + "image-illumination": "artificial light", + "image-item-identification-scheme": "EVENT_SENSOR_DATE_TIME.jpg", + "image-marine-zone": "seafloor", + "image-navigation": "beacon", + "image-quality": "raw", + "image-pixel-magnitude": "mm", + "image-scale-reference": "laser marker", + "image-datetime": "2019-03-04 08:37:24.000000", + "image-latitude": 11.9294422, + "image-longitude": -117.0407515, + "image-altitude-meters": -4094.5 + }, + "image-set-items": { + "SO268-1_21-1_OFOS_SO_CAM-1_20190304_083724.JPG": [{ + "image-handle": "", + "image-area-square-meters": 21.6994, + "image-average-color": [168, 187, 144], + "image-datetime": "2019-03-04 08:37:24.000000", + "image-altitude-meters": -4094.5, + "image-entropy": 0.8174957092476102, + "image-hash-sha256": "83f30eb35d1325c44c85fba0cf478825c0a629d20177a945069934f6cd07e087", + "image-latitude": 11.9294422, + "image-longitude": -117.0407515, + "image-mpeg7-colorstatistic": [27.0, 255.0, 38.0, 255.0, 36.0, 255.0, 169.3751983642578, 211.97219848632812, 198.2913360595703, 25.55811309814453, 31.31110954284668, 37.18994140625, 177.0, 224.0, 212.0, 0.8022223711013794, 0.806853175163269, 0.8450505137443542], + "image-uuid": "c6b8d981-05c7-449f-85a9-906ab866bfb6" + }, + { + "image-datetime": "2019-03-04 08:37:25.000000", + "image-latitude": 11.9294422, + "image-longitude": -117.0407515 + } + ], + "SO268-1_21-1_OFOS_SO_CAM-1_20190304_083734.JPG": [{ + "image-handle": "", + "image-area-square-meters": 29.6263, + "image-average-color": [116, 141, 114], + "image-datetime": "2019-03-04 08:37:34.000000", + "image-altitude-meters": -4094.6, + "image-entropy": 0.8340960692175852, + "image-hash-sha256": "819e1810dccd9025310d7841a994b94bcdc438ae74ec5095ce01f1bd46143c4e", + "image-latitude": 11.9294418, + "image-longitude": -117.040753, + "image-uuid": "daad4a74-5c16-49d0-9775-efa67f0459f4" + }, + { + "image-datetime": "2019-03-04 08:37:35.000000", + "image-latitude": 11.9294418, + "image-longitude": -117.040753 + } + ] + } +} \ No newline at end of file diff --git a/standard/iFDO-icons.md b/standard/iFDO-icons.md new file mode 100644 index 0000000000000000000000000000000000000000..4afd0026168c723ebf7926da489a7496b61ab1a6 --- /dev/null +++ b/standard/iFDO-icons.md @@ -0,0 +1,29 @@ +# Visualizing iFDO information with icons +Some of the iFDO fields require using well-defined values for those fields as described in the tables on the +specific iFDO sections. For these well-defined values, icons were created to enable visualizing this capture +information in web interfaces or data processing reports. These icons are available in the resources folder and an +overview is given here. You are free to use these icons. They are released publicly under CC-0. + +## iFDO core icons + +```json-schema-icons-gen +schema: schema/ifdo-core.json +icon_path: icons +external_property_page: documentation/iFDO-core.md/ +``` + +## iFDO content icons + +```json-schema-icons-gen +schema: schema/annotation.json +icon_path: icons +external_property_page: documentation/iFDO-content.md/ +``` + +## iFDO capture icons + +```json-schema-icons-gen +schema: schema/ifdo-capture.json +icon_path: icons +external_property_page: documentation/iFDO-capture.md/ +``` \ No newline at end of file diff --git a/docs/ifdos/svgs/image-acquisition_photo.svg b/standard/icons/image-acquisition_photo.svg similarity index 100% rename from docs/ifdos/svgs/image-acquisition_photo.svg rename to standard/icons/image-acquisition_photo.svg diff --git a/docs/ifdos/svgs/image-acquisition_slide.svg b/standard/icons/image-acquisition_slide.svg similarity index 100% rename from docs/ifdos/svgs/image-acquisition_slide.svg rename to standard/icons/image-acquisition_slide.svg diff --git a/docs/ifdos/svgs/image-acquisition_video.svg b/standard/icons/image-acquisition_video.svg similarity index 100% rename from docs/ifdos/svgs/image-acquisition_video.svg rename to standard/icons/image-acquisition_video.svg diff --git a/docs/ifdos/svgs/image-annotation-geometry_polygon.svg b/standard/icons/image-annotations-shape_polygon.svg similarity index 100% rename from docs/ifdos/svgs/image-annotation-geometry_polygon.svg rename to standard/icons/image-annotations-shape_polygon.svg diff --git a/docs/ifdos/svgs/image-annotation-geometry_bounding-box.svg b/standard/icons/image-annotations-shape_rectangle.svg similarity index 100% rename from docs/ifdos/svgs/image-annotation-geometry_bounding-box.svg rename to standard/icons/image-annotations-shape_rectangle.svg diff --git a/docs/ifdos/svgs/image-annotation-geometry_single-pixel.svg b/standard/icons/image-annotations-shape_single-pixel.svg similarity index 100% rename from docs/ifdos/svgs/image-annotation-geometry_single-pixel.svg rename to standard/icons/image-annotations-shape_single-pixel.svg diff --git a/docs/ifdos/svgs/image-annotation-geometry_whole-image.svg b/standard/icons/image-annotations-shape_whole-image.svg similarity index 100% rename from docs/ifdos/svgs/image-annotation-geometry_whole-image.svg rename to standard/icons/image-annotations-shape_whole-image.svg diff --git a/docs/ifdos/svgs/image-capture-mode_manual.svg b/standard/icons/image-capture-mode_manual.svg similarity index 100% rename from docs/ifdos/svgs/image-capture-mode_manual.svg rename to standard/icons/image-capture-mode_manual.svg diff --git a/docs/ifdos/svgs/image-capture-mode_timer-and-manual.svg b/standard/icons/image-capture-mode_mixed.svg similarity index 100% rename from docs/ifdos/svgs/image-capture-mode_timer-and-manual.svg rename to standard/icons/image-capture-mode_mixed.svg diff --git a/docs/ifdos/svgs/image-capture-mode_timer.svg b/standard/icons/image-capture-mode_timer.svg similarity index 100% rename from docs/ifdos/svgs/image-capture-mode_timer.svg rename to standard/icons/image-capture-mode_timer.svg diff --git a/docs/ifdos/svgs/image-deployment_experiment.svg b/standard/icons/image-deployment_experiment.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_experiment.svg rename to standard/icons/image-deployment_experiment.svg diff --git a/docs/ifdos/svgs/image-deployment_exploration.svg b/standard/icons/image-deployment_exploration.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_exploration.svg rename to standard/icons/image-deployment_exploration.svg diff --git a/docs/ifdos/svgs/image-deployment_mapping.svg b/standard/icons/image-deployment_mapping.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_mapping.svg rename to standard/icons/image-deployment_mapping.svg diff --git a/docs/ifdos/svgs/image-deployment_sampling.svg b/standard/icons/image-deployment_sampling.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_sampling.svg rename to standard/icons/image-deployment_sampling.svg diff --git a/docs/ifdos/svgs/image-deployment_stationary.svg b/standard/icons/image-deployment_stationary.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_stationary.svg rename to standard/icons/image-deployment_stationary.svg diff --git a/docs/ifdos/svgs/image-deployment_survey.svg b/standard/icons/image-deployment_survey.svg similarity index 100% rename from docs/ifdos/svgs/image-deployment_survey.svg rename to standard/icons/image-deployment_survey.svg diff --git a/docs/ifdos/svgs/image-illumination_artificial.svg b/standard/icons/image-illumination_artificial light.svg similarity index 100% rename from docs/ifdos/svgs/image-illumination_artificial.svg rename to standard/icons/image-illumination_artificial light.svg diff --git a/docs/ifdos/svgs/image-illumination_mixed.svg b/standard/icons/image-illumination_mixed light.svg similarity index 100% rename from docs/ifdos/svgs/image-illumination_mixed.svg rename to standard/icons/image-illumination_mixed light.svg diff --git a/docs/ifdos/svgs/image-illumination_sun.svg b/standard/icons/image-illumination_sunlight.svg similarity index 100% rename from docs/ifdos/svgs/image-illumination_sun.svg rename to standard/icons/image-illumination_sunlight.svg diff --git a/docs/ifdos/svgs/image-license_CC-0.svg b/standard/icons/image-license-name_CC-0.svg similarity index 100% rename from docs/ifdos/svgs/image-license_CC-0.svg rename to standard/icons/image-license-name_CC-0.svg diff --git a/docs/ifdos/svgs/image-license_CC-BY.svg b/standard/icons/image-license-name_CC-BY.svg similarity index 100% rename from docs/ifdos/svgs/image-license_CC-BY.svg rename to standard/icons/image-license-name_CC-BY.svg diff --git a/docs/ifdos/svgs/image-marine-zone_atmosphere.svg b/standard/icons/image-marine-zone_atmosphere.svg similarity index 100% rename from docs/ifdos/svgs/image-marine-zone_atmosphere.svg rename to standard/icons/image-marine-zone_atmosphere.svg diff --git a/docs/ifdos/svgs/image-marine-zone_laboratory.svg b/standard/icons/image-marine-zone_laboratory.svg similarity index 100% rename from docs/ifdos/svgs/image-marine-zone_laboratory.svg rename to standard/icons/image-marine-zone_laboratory.svg diff --git a/docs/ifdos/svgs/image-marine-zone_seasurface.svg b/standard/icons/image-marine-zone_sea surface.svg similarity index 100% rename from docs/ifdos/svgs/image-marine-zone_seasurface.svg rename to standard/icons/image-marine-zone_sea surface.svg diff --git a/docs/ifdos/svgs/image-marine-zone_seafloor.svg b/standard/icons/image-marine-zone_seafloor.svg similarity index 100% rename from docs/ifdos/svgs/image-marine-zone_seafloor.svg rename to standard/icons/image-marine-zone_seafloor.svg diff --git a/docs/ifdos/svgs/image-marine-zone_watercolumn.svg b/standard/icons/image-marine-zone_water column.svg similarity index 100% rename from docs/ifdos/svgs/image-marine-zone_watercolumn.svg rename to standard/icons/image-marine-zone_water column.svg diff --git a/docs/ifdos/svgs/image-navigation_beacon.svg b/standard/icons/image-navigation_beacon.svg similarity index 100% rename from docs/ifdos/svgs/image-navigation_beacon.svg rename to standard/icons/image-navigation_beacon.svg diff --git a/docs/ifdos/svgs/image-navigation_reconstructed.svg b/standard/icons/image-navigation_reconstructed.svg similarity index 100% rename from docs/ifdos/svgs/image-navigation_reconstructed.svg rename to standard/icons/image-navigation_reconstructed.svg diff --git a/docs/ifdos/svgs/image-navigation_satellite.svg b/standard/icons/image-navigation_satellite.svg similarity index 100% rename from docs/ifdos/svgs/image-navigation_satellite.svg rename to standard/icons/image-navigation_satellite.svg diff --git a/docs/ifdos/svgs/image-navigation_transponder.svg b/standard/icons/image-navigation_transponder.svg similarity index 100% rename from docs/ifdos/svgs/image-navigation_transponder.svg rename to standard/icons/image-navigation_transponder.svg diff --git a/docs/ifdos/svgs/image-resolution_cm.svg b/standard/icons/image-pixel-magnitude_cm.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_cm.svg rename to standard/icons/image-pixel-magnitude_cm.svg diff --git a/docs/ifdos/svgs/image-resolution_dam.svg b/standard/icons/image-pixel-magnitude_dam.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_dam.svg rename to standard/icons/image-pixel-magnitude_dam.svg diff --git a/docs/ifdos/svgs/image-resolution_dm.svg b/standard/icons/image-pixel-magnitude_dm.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_dm.svg rename to standard/icons/image-pixel-magnitude_dm.svg diff --git a/docs/ifdos/svgs/image-resolution_hm.svg b/standard/icons/image-pixel-magnitude_hm.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_hm.svg rename to standard/icons/image-pixel-magnitude_hm.svg diff --git a/docs/ifdos/svgs/image-resolution_km.svg b/standard/icons/image-pixel-magnitude_km.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_km.svg rename to standard/icons/image-pixel-magnitude_km.svg diff --git a/docs/ifdos/svgs/image-resolution_m.svg b/standard/icons/image-pixel-magnitude_m.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_m.svg rename to standard/icons/image-pixel-magnitude_m.svg diff --git a/docs/ifdos/svgs/image-resolution_mm.svg b/standard/icons/image-pixel-magnitude_mm.svg similarity index 100% rename from docs/ifdos/svgs/image-resolution_mm.svg rename to standard/icons/image-pixel-magnitude_mm.svg diff --git "a/docs/ifdos/svgs/image-resolution_\316\274m.svg" "b/standard/icons/image-pixel-magnitude_\302\265m.svg" similarity index 100% rename from "docs/ifdos/svgs/image-resolution_\316\274m.svg" rename to "standard/icons/image-pixel-magnitude_\302\265m.svg" diff --git a/docs/ifdos/svgs/image-quality_processed.svg b/standard/icons/image-quality_processed.svg similarity index 100% rename from docs/ifdos/svgs/image-quality_processed.svg rename to standard/icons/image-quality_processed.svg diff --git a/docs/ifdos/svgs/image-quality_product.svg b/standard/icons/image-quality_product.svg similarity index 100% rename from docs/ifdos/svgs/image-quality_product.svg rename to standard/icons/image-quality_product.svg diff --git a/docs/ifdos/svgs/image-quality_raw.svg b/standard/icons/image-quality_raw.svg similarity index 100% rename from docs/ifdos/svgs/image-quality_raw.svg rename to standard/icons/image-quality_raw.svg diff --git a/docs/ifdos/svgs/image-scale-reference_3D camera.svg b/standard/icons/image-scale-reference_3D camera.svg similarity index 100% rename from docs/ifdos/svgs/image-scale-reference_3D camera.svg rename to standard/icons/image-scale-reference_3D camera.svg diff --git a/docs/ifdos/svgs/image-scale-reference_calibrated camera.svg b/standard/icons/image-scale-reference_calibrated camera.svg similarity index 100% rename from docs/ifdos/svgs/image-scale-reference_calibrated camera.svg rename to standard/icons/image-scale-reference_calibrated camera.svg diff --git a/docs/ifdos/svgs/image-scale-reference_laser marker.svg b/standard/icons/image-scale-reference_laser marker.svg similarity index 100% rename from docs/ifdos/svgs/image-scale-reference_laser marker.svg rename to standard/icons/image-scale-reference_laser marker.svg diff --git a/docs/ifdos/svgs/image-scale-reference_optical flow.svg b/standard/icons/image-scale-reference_optical flow.svg similarity index 100% rename from docs/ifdos/svgs/image-scale-reference_optical flow.svg rename to standard/icons/image-scale-reference_optical flow.svg diff --git a/docs/ifdos/svgs/image-spectral-resolution_grayscale.svg b/standard/icons/image-spectral-resolution_grayscale.svg similarity index 100% rename from docs/ifdos/svgs/image-spectral-resolution_grayscale.svg rename to standard/icons/image-spectral-resolution_grayscale.svg diff --git a/docs/ifdos/svgs/image-spectral-resolution_hyper-spectral.svg b/standard/icons/image-spectral-resolution_hyper-spectral.svg similarity index 100% rename from docs/ifdos/svgs/image-spectral-resolution_hyper-spectral.svg rename to standard/icons/image-spectral-resolution_hyper-spectral.svg diff --git a/docs/ifdos/svgs/image-spectral-resolution_multi-spectral.svg b/standard/icons/image-spectral-resolution_multi-spectral.svg similarity index 100% rename from docs/ifdos/svgs/image-spectral-resolution_multi-spectral.svg rename to standard/icons/image-spectral-resolution_multi-spectral.svg diff --git a/docs/ifdos/svgs/image-spectral-resolution_rgb.svg b/standard/icons/image-spectral-resolution_rgb.svg similarity index 100% rename from docs/ifdos/svgs/image-spectral-resolution_rgb.svg rename to standard/icons/image-spectral-resolution_rgb.svg diff --git a/standard/schema/annotation.json b/standard/schema/annotation.json new file mode 100644 index 0000000000000000000000000000000000000000..bafdfdd73afd754d9bb6fb2e96bd72bea7102609 --- /dev/null +++ b/standard/schema/annotation.json @@ -0,0 +1,158 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/annotation.json", + "title": "Annotations of images", + "description": "A schema to establish a format for annotations within images (photos and videos) of different shape and by different annotators", + "type": "object", + "properties": { + "image-annotation-labels": { + "description": "All the labels used in the image-annotations. Specified by an id (e.g. AphiaID), a human-readable name and an optional description.", + "type": "array", + "items": { + "$ref": "#/$defs/label" + } + }, + "image-annotation-creators": { + "description": "All the annotators that created image-annotations. Specified by an id (e.g. ORCID), a human-readable name and an optional type specifying the annotator's expertise.", + "type": "array", + "items": { + "$ref": "#/$defs/annotator" + } + }, + "image-annotations": { + "description": "This field stores all annotations as a list of dictionaries of 3-4 fields: shape, coordinates, labels and (optional) frames. See further explanations below. The list of labels specifies the IDs or names of objects and annotators and their confidence. These should be specified in an `image-annotation-labels` and `image-annotation-creators` field (see above) to provide more information on the values used in these fields.", + "type": "array", + "items": { + "type": "object", + "properties": { + "shape": { + "description": "The annotation shape is specified by a keyword (allowed values: see enum).", + "type": "string", + "anyOf": [ + { + "const": "single-pixel", + "description": "Single points in the images were marked" + }, + { + "const": "polyline", + "description": "" + }, + { + "const": "polygon", + "description": "A detailed outline was drawn around objects of interest" + }, + { + "const": "circle", + "description": "" + }, + { + "const": "rectangle", + "description": "A bounding box was drawn around objects of interest" + }, + { + "const": "ellipse", + "description": "" + }, + { + "const": "whole-image", + "description": "The entire image was annotated without defining a region of interest" + } + ] + }, + "coordinates": { + "description": "The pixel coordinates of one annotation. The top-left corner of an image is the (0,0) coordinate. The x-axis is the horizontal axis. Pixel coordinates may be fractional. Coordinates are to be given as a list of lists (only one element for photos, optionally multiple elements for videos). The required number of pixel coordinates is defined by the shape (0 for whole-image, 2 for single-pixel, 3 for circle, 8 for ellipse/rectangle, 4 or more for polyline, 8 or more for polygon). The third coordinate value of a circle defines the radius. The first and last coordinates of a polygon must be equal. Format: [[p1.x,p1.y,p2x,p2.y,...]..]", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "number" + } + } + }, + "labels": { + "description": "The list of labels assigned to annotations by annotators", + "type": "array", + "items": { + "$ref": "#/$defs/annotation-label" + } + }, + "frames": { + "type": "array", + "items": { + "type": "number", + "minimum": 0 + }, + "description": "(only required for video annotations) Frame times (in seconds from the beginning of a video) of a video annotation. Each frame time is linked to one entry in `image-annotations:coordinates` at the same position in the list, which specifies the current coordinates of the annotation at that frame. Format: [f1,...]" + } + } + } + } + }, + "$defs": { + "annotation-label": { + "type": "object", + "required": [ + "label", + "annotator", + "created-at" + ], + "properties": { + "label": { + "description": "A unique identifier to a semantic label", + "type": "string" + }, + "annotator": { + "description": "A unique identifier to an annotation creator, e.g. orcid URL or handle to ML model", + "type": "string" + }, + "created-at": { + "description": "The date-time stamp of label creation", + "type": "string", + "format": "date-time" + }, + "confidence": { + "description": "A numerical confidence estimate of the validity of the label between 0 (untrustworthy) and 1 (100% certainty)", + "type": "number" + } + } + }, + "label": { + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "description": "A unique identifier to a semantic label", + "type": "string" + }, + "name": { + "description": "A human-readable name for the semantic label", + "type": "string" + }, + "info": { + "description": "A description on what this semantic label represents", + "type": "string" + } + } + }, + "annotator": { + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "description": "A unique identifier to an annotation creator, e.g. orcid URL or handle to ML model", + "type": "string" + }, + "name": { + "description": "A human-readable name for the annotator (identifying the specific human or machine)", + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/standard/schema/ifdo-capture.json b/standard/schema/ifdo-capture.json new file mode 100644 index 0000000000000000000000000000000000000000..a7c575bbd6c0062b92483eed762182c743e48a32 --- /dev/null +++ b/standard/schema/ifdo-capture.json @@ -0,0 +1,578 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/ifdo-capture.json", + "type": "object", + "properties": { + "image-acquisition": { + "description": "photo: still images, video: moving images, slide: microscopy images / slide scans", + "type": "string", + "anyOf": [ + { + "const": "photo", + "description": "The image set contains still images" + }, + { + "const": "video", + "description": "The image set contains moving images" + }, + { + "const": "slide", + "description": "The image set contains microscopy images / slide scans" + } + ] + }, + "image-quality": { + "description": "raw: straight from the sensor, processed: QA/QC'd, product: image data ready for interpretation", + "type": "string", + "anyOf": [ + { + "const": "raw", + "description": "The images in the image set come straight from the sensor" + }, + { + "const": "processed", + "description": "The images in the image set have been QA/QCd" + }, + { + "const": "product", + "description": "The images in the image set are ready for interpretation" + } + ] + }, + "image-deployment": { + "description": "mapping: planned path execution along 2-3 spatial axes, stationary: fixed spatial position, survey: planned path execution along free path, exploration: unplanned path execution, experiment: observation of manipulated environment, sampling: ex-situ imaging of samples taken by other method", + "type": "string", + "anyOf": [ + { + "const": "mapping", + "description": "The camera followed a planned path execution along 2-3 spatial axes" + }, + { + "const": "stationary", + "description": "The camera remained in a fixed spatial position" + }, + { + "const": "survey", + "description": "The camera followed a planned path execution along a free path" + }, + { + "const": "exploration", + "description": "The camera followed an unplanned path execution" + }, + { + "const": "experiment", + "description": "The camera observed a manipulation of the environment" + }, + { + "const": "sampling", + "description": "The camera imaging samples taken by other method ex-situ" + } + ] + }, + "image-navigation": { + "description": "satellite: GPS/Galileo etc., beacon: USBL etc., transponder: LBL etc., reconstructed: position estimated from other measures like cable length and course over ground", + "type": "string", + "anyOf": [ + { + "const": "satellite", + "description": "Position data was created from satellite information (GPS, Galileo, ...) for the sea surface" + }, + { + "const": "beacon", + "description": "Position data was created from underwater beacons (USBL, ...) for an underwater position" + }, + { + "const": "transponder", + "description": "Position data was created from underwater beacons (USBL, LBL, ...) for an underwater position" + }, + { + "const": "reconstructed", + "description": "Position data was estimated from other measures like cable length and course over ground" + } + ] + }, + "image-scale-reference": { + "description": "3D camera: the imaging system provides scale directly, calibrated camera: image data and additional external data like object distance provide scale together, laser marker: scale information is embedded in the visual data, optical flow: scale is computed from the relative movement of the images and the camera navigation data", + "type": "string", + "anyOf": [ + { + "const": "3D camera", + "description": "Meter-scale in the images was determined by 3D imaging / reconstruction" + }, + { + "const": "calibrated camera", + "description": "Meter-scale in the images was determined by image data and additional external data like object distance" + }, + { + "const": "laser marker", + "description": "Meter-scale in the images was determined by laser markers visible in the images" + }, + { + "const": "optical flow", + "description": "Meter-scale in the images was determined from the relative movement of the images and the camera navigation data" + } + ] + }, + "image-illumination": { + "description": "sunlight: the scene is only illuminated by the sun, artificial light: the scene is only illuminated by artificial light, mixed light: both sunlight and artificial light illuminate the scene", + "type": "string", + "anyOf": [ + { + "const": "sunlight", + "description": "The scene is only illuminated by the sun" + }, + { + "const": "artificial light", + "description": "The scene is only illuminated by artificial light" + }, + { + "const": "mixed light", + "description": "The scene is illuminated by both sunlight and artificial light" + } + ] + }, + "image-pixel-magnitude": { + "description": "average size of one pixel of an image", + "type": "string", + "anyOf": [ + { + "const": "km", + "description": "The average size of a pixel in the image set is on the order of 1 km" + }, + { + "const": "hm", + "description": "The average size of a pixel in the image set is on the order of 1 hm = 100 m" + }, + { + "const": "dam", + "description": "The average size of a pixel in the image set is on the order of 1 dam = 10 m" + }, + { + "const": "m", + "description": "The average size of a pixel in the image set is on the order of 1 m" + }, + { + "const": "dm", + "description": "The average size of a pixel in the image set is on the order of 1 dm = 0.1 m" + }, + { + "const": "cm", + "description": "The average size of a pixel in the image set is on the order of 1 cm" + }, + { + "const": "mm", + "description": "The average size of a pixel in the image set is on the order of 1 mm" + }, + { + "const": "\u00b5m", + "description": "The average size of a pixel in the image set is on the order of 1 µm" + } + ] + }, + "image-marine-zone": { + "description": "seafloor: images taken in/on/right above the seafloor, water column: images taken in the free water without the seafloor or the sea surface in sight, sea surface: images taken right below the sea surface, atmosphere: images taken outside of the water, laboratory: images taken ex-situ", + "type": "string", + "anyOf": [ + { + "const": "seafloor", + "description": "The images were taken right below the sea surface" + }, + { + "const": "water column", + "description": "The images were taken in the water column without the seafloor or the sea surface in sight" + }, + { + "const": "sea surface", + "description": "The images were taken in/on/right above the seafloor" + }, + { + "const": "atmosphere", + "description": "The images were taken outside of the water" + }, + { + "const": "laboratory", + "description": "The images were taken ex-situ" + } + ] + }, + "image-spectral-resolution": { + "description": "grayscale: single channel imagery, rgb: three channel imagery, multi-spectral: 4-10 channel imagery, hyper-spectral: 10+ channel imagery", + "type": "string", + "anyOf": [ + { + "const": "grayscale", + "description": "The images consist of one color channel" + }, + { + "const": "rgb", + "description": "The images consist of three color channels" + }, + { + "const": "multi-spectral", + "description": "The images consist of 4-10 color channels" + }, + { + "const": "hyper-spectral", + "description": "The images consist of more than 10 channels" + } + ] + }, + "image-capture-mode": { + "description": "whether the time points of image capture were systematic, human-triggered or both", + "type": "string", + "anyOf": [ + { + "const": "timer", + "description": "Image-acquisition was triggered by a timer" + }, + { + "const": "manual", + "description": "Image-acquisition was triggered by a human controller" + }, + { + "const": "mixed", + "description": "Image-acquisition was triggered by both a timer and a human-controller" + } + ] + }, + "image-fauna-attraction": { + "description": "Allowed: none, baited, light", + "type": "string", + "anyOf": [ + { + "const": "none", + "description": "" + }, + { + "const": "baited", + "description": "" + }, + { + "const": "light", + "description": "" + } + ] + }, + "image-area-square-meters": { + "description": "The footprint of the entire image in square meters", + "type": "number", + "exclusiveMinimum": 0 + }, + "image-meters-above-ground": { + "description": "Distance of the camera to the seafloor in meters", + "type": "number" + }, + "image-acquisition-settings": { + "description": "All the information that is recorded by the camera in the EXIF, IPTC etc. As a dict. Includes ISO, aperture, etc.", + "type": "object" + }, + "image-camera-yaw-degrees": { + "description": "Camera view yaw angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \"right-hand rule\". I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north.", + "type": "number" + }, + "image-camera-pitch-degrees": { + "description": "Camera view pitch angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \"right-hand rule\". I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north.", + "type": "number" + }, + "image-camera-roll-degrees": { + "description": "Camera view roll angle. Rotation of camera coordinates (x,y,z = top, right, line of sight) with respect to NED coordinates (x,y,z = north,east,down) in accordance with the yaw,pitch,roll rotation order convention: 1. yaw around z, 2. pitch around rotated y, 3. roll around rotated x. Rotation directions according to \"right-hand rule\". I.e. for yaw,pitch,roll = 0,0,0 camera is facing downward with top side towards north.", + "type": "number" + }, + "image-overlap-fraction": { + "description": "The average overlap of two consecutive images i and j as the area images in both of the images (A_i * A_j) divided by the total area images by the two images (A_i + A_j - A_i * A_j): f = A_i * A_j / (A_i + A_j - A_i * A_j) -> 0 if no overlap. 1 if complete overlap", + "type": "number", + "exclusiveMinimum": 0, + "maximum": 1 + }, + "image-datetime-format": { + "description": "A date time format string in Python notation to specify a date time format used throughout the iFDO file that differs from the default one '%Y-%m-%d %H:%M:%S.%f'. Make sure to reach second-accuracy with your date times!", + "type": "string" + }, + "image-camera-pose": { + "description": "Information required to specify camera pose. Details given in properties.", + "type": "object", + "properties": { + "pose-utm-zone": { + "description": "The UTM zone number", + "type": "string" + }, + "pose-utm-epsg": { + "description": "The EPSG code of the UTM zone", + "type": "string" + }, + "pose-utm-east-north-up-meters": { + "description": "The position of the camera center in UTM coordinates.", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "pose-absolute-orientation-utm-matrix": { + "description": "3x3 row-major float rotation matrix that transforms a direction in camera coordinates (x,y,z = right,down,line of sight) into a direction in UTM coordinates (x,y,z = easting,northing,up)}", + "type": "array", + "minItems": 9, + "maxItems": 9, + "items": { + "type": "number" + } + } + } + }, + "image-camera-housing-viewport": { + "description": "Information on the camera pressure housing viewport (the glass). Details given in properties.", + "type": "object", + "properties": { + "viewport-type": { + "description": "e.g.: flat port, dome port, other", + "type": "string" + }, + "viewport-optical-density": { + "description": "Unit-less optical density number (1.0=vacuum)", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "viewport-thickness-millimeters": { + "description": "Thickness of viewport in millimeters", + "type": "number", + "exclusiveMinimum": 0 + }, + "viewport-extra-description": { + "description": "A textual description of the viewport used", + "type": "string" + } + } + }, + "image-flatport-parameters": { + "description": "Information required to specify the characteristics of a flat port camera housing. Details given in properties.", + "type": "object", + "properties": { + "flatport-lens-port-distance-millimeters": { + "description": "The distance between the front of the camera lens and the inner side of the housing viewport in millimeters.", + "type": "number", + "exclusiveMinimum": 0 + }, + "flatport-interface-normal-direction": { + "description": "3D direction vector to specify how the view direction of the lens intersects with the viewport (unit-less, (0,0,1) is aligned)", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "flatport-extra-description": { + "description": "A textual description of the flat port used", + "type": "string" + } + } + }, + "image-domeport-parameters": { + "description": "Information required to specify the characteristics of a dome port camera housing. Details given in properties.", + "type": "object", + "properties": { + "domeport-outer-radius-millimeters": { + "description": "Outer radius of the dome port - the part that has contact with the water.", + "type": "number" + }, + "domeport-decentering-offset-xyz-millimeters": { + "description": "3D offset vector of the camera center from the dome port center in millimeters", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "domeport-extra-description": { + "description": "A textual description of the dome port used", + "type": "string" + } + } + }, + "image-camera-calibration-model": { + "description": "Information required to specify the camera calibration model. Details given in properties.", + "type": "object", + "properties": { + "calibration-model-type": { + "description": "e.g.: rectilinear air, rectilinear water, fisheye air, fisheye water, other", + "type": "string" + }, + "calibration-focal-length-xy-pixel": { + "description": "2D focal length in pixels", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "number" + } + }, + "calibration-principal-point-xy-pixel": { + "description": "2D principal point of the calibration in pixels (top left pixel center is 0,0, x right, y down)", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "number" + } + }, + "calibration-distortion-coefficients": { + "description": "rectilinear: k1, k2, p1, p2, k3, k4, k5, k6, fisheye: k1, k2, k3, k4", + "type": "array", + "items": { + "type": "number" + } + }, + "calibration-approximate-field-of-view-water-xy-degree": { + "description": "Proxy for pixel to meter conversion, and as backup", + "type": "array", + "items": { + "type": "number" + } + }, + "calibration-model-extra-description": { + "description": "Explain model, or if lens parameters are in mm rather than in pixel", + "type": "string" + } + } + }, + "image-photometric-calibration": { + "description": "Information required to specify the photometric calibration. Details given in properties.", + "type": "object", + "properties": { + "photometric-sequence-white-balancing": { + "description": "A text on how white-balancing was done.", + "type": "string" + }, + "photometric-exposure-factor-RGB": { + "description": "RGB factors applied to this image, product of ISO, exposure time, relative white balance", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "photometric-sequence-illumination-type": { + "description": "e.g. constant artificial, globally adapted artificial, individually varying light sources, sunlight, mixed)", + "type": "string" + }, + "photometric-sequence-illumination-description": { + "description": "A text on how the image sequence was illuminated", + "type": "string" + }, + "photometric-illumination-factor-RGB": { + "description": "RGB factors applied to artificial lights for this image", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "number" + } + }, + "photometric-water-properties-description": { + "description": "A text describing the photometric properties of the water within which the images were capture", + "type": "string" + } + } + }, + "image-objective": { + "description": "A general description of the aims and objectives of the study, as they pertain to biology and method scope. This should define the primary and secondary data to be measured and to what precision.", + "type": "string" + }, + "image-target-environment": { + "description": "A description, delineation, and definition of the habitat or environment of study, including boundaries of such", + "type": "string" + }, + "image-target-timescale": { + "description": "A description, delineation, and definition of the period, interval or temporal environment of the study.", + "type": "string" + }, + "image-spatial-constraints": { + "description": "A description / definition of the spatial extent of the study area (inside which the photographs were captured), including boundaries and reasons for constraints (e.g. scientific, practical)", + "type": "string" + }, + "image-temporal-constraints": { + "description": "A description / definition of the temporal extent, including boundaries and reasons for constraints (e.g. scientific, practical)", + "type": "string" + }, + "image-time-synchronisation": { + "description": "Synchronisation procedure and determined time offsets between camera recording values and UTC", + "type": "string" + }, + "image-item-identification-scheme": { + "description": "How the images file names are constructed. Should be like this `image-project_image-event_image-sensor_image-datetime.ext`", + "type": "string" + }, + "image-curation-protocol": { + "description": "A description of the image and metadata curation steps and results", + "type": "string" + }, + "image-visual-constraints": { + "type": "string", + "description": "An explanation how the images might be degraded (turbidity, blocked view, ...)" + }, + "image-set-min-latitude-degrees": { + "type": "number", + "minimum": -90, + "maximum": 90, + "description": "The lower bounding box latitude enclosing all images in the set" + }, + "image-set-max-latitude-degrees": { + "type": "number", + "minimum": -90, + "maximum": 90, + "description": "The upper bounding box latitude enclosing all images in the set" + }, + "image-set-min-longitude-degrees": { + "type": "number", + "minimum": -180, + "maximum": 180, + "description": "The lower bounding box longitude enclosing all images in the set" + }, + "image-set-max-longitude-degrees": { + "type": "number", + "minimum": -180, + "maximum": 180, + "description": "The upper bounding box longitude enclosing all images in the set" + }, + "image-set-related-material": { + "type": "array", + "description": "Links to other resources that are related to this image set.", + "items": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri", + "description": "The URI pointing to a related resource" + }, + "title": { + "type": "string", + "description": "A name characterising the resource that is pointed to" + }, + "relation": { + "type": "string", + "description": "A textual explanation how this material is related to this image set" + } + }, + "required": [ + "uri", + "title", + "relation" + ] + } + }, + "image-set-provenance": { + "$ref": "https://marine-imaging.com/fair/schemas/provenance.json" + } + }, + "@context": [ + { + "@vocab": "https://schema.org", + "image-acquisition": "ImageObject" + } + ] +} \ No newline at end of file diff --git a/standard/schema/ifdo-content.json b/standard/schema/ifdo-content.json new file mode 100644 index 0000000000000000000000000000000000000000..943cd83de10bd2e9b0aba5e05be5adfa15b86a98 --- /dev/null +++ b/standard/schema/ifdo-content.json @@ -0,0 +1,87 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/ifdo-content.json", + "type": "object", + "properties": { + "image-entropy": { + "description": "Information content of an image / frame according to Shannon entropy.", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "image-particle-count": { + "description": "Counts of single particles/objects in an image / frame", + "type": "integer", + "minimum": 0 + }, + "image-average-color": { + "description": "The average colour for each image / frame and the n channels of an image (e.g. 3 for RGB)", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": { + "type": "integer", + "minimum": 0, + "maximum": 256 + } + }, + "image-mpeg7-colorlayout": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-colorstatistic": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-colorstructure": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-dominantcolor": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-edgehistogram": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-homogeneoustexture": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-mpeg7-scalablecolor": { + "description": "An nD feature vector per image / frame of varying dimensionality according to the chosen descriptor settings.", + "type": "array", + "items": { + "type": "number" + } + }, + "image-annotation-labels": { + "$ref": "https://marine-imaging.com/fair/schemas/annotation.json#/properties/image-annotation-labels" + }, + "image-annotation-creators": { + "$ref": "https://marine-imaging.com/fair/schemas/annotation.json#/properties/image-annotation-creators" + }, + "image-annotations": { + "$ref": "https://marine-imaging.com/fair/schemas/annotation.json#/properties/image-annotations" + } + } +} \ No newline at end of file diff --git a/standard/schema/ifdo-core.json b/standard/schema/ifdo-core.json new file mode 100644 index 0000000000000000000000000000000000000000..7dbd8a36a6ba57fa227592e9c0b6812d8eb99f7e --- /dev/null +++ b/standard/schema/ifdo-core.json @@ -0,0 +1,274 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/ifdo-core.json", + "type": "object", + "properties": { + "image-set-name": { + "description": "A unique name for the image set, should include image-project, image-event, image-sensor and optionally the purpose of imaging", + "type": "string" + }, + "image-set-uuid": { + "description": "A random UUID assigned to the entire image set", + "type": "string", + "format": "uuid" + }, + "image-set-handle": { + "description": "A Handle URL (suggested: using the image-set-uuid) to point to the landing page of the data set", + "type": "string", + "format": "uri" + }, + "image-set-ifdo-version": { + "description": "The semantic version information of the iFDO standard used.", + "type": "string" + }, + "image-datetime": { + "description": "Full UTC datetime of image acquisition (or start time of a video) as in ISO8601. The default format here is 'YYYY-MM-DD hh:mm:ss.sss' with a space between date and time as in ISO 8601:2004. Other formats may be used if defined in the field 'image-datetime-format'.", + "type": "string" + }, + "image-handle": { + "type": "string", + "format": "uri", + "description": "The URI pointing to a downloadable version of the image data" + }, + "image-latitude": { + "description": "Y-coordinate of the camera center in decimal degrees: D.DDDDDDD (use at least seven significant digits that is ca. 1cm resolution on Earth)", + "type": "number", + "minimum": -90, + "maximum": 90 + }, + "image-longitude": { + "description": "X-coordinate of the camera center in decimal degrees: D.DDDDDDD (use at least seven significant digits that is ca. 1cm resolution on Earth)", + "type": "number", + "minimum": -180, + "maximum": 180 + }, + "image-altitude-meters": { + "description": "Z-coordinate of camera center in meters. Has negative values when camera is below sea level. Has positive values when the camera is above sea level.", + "type": "number" + }, + "image-coordinate-reference-system": { + "description": "The coordinate reference system, e.g. EPSG:4326", + "type": "string" + }, + "image-coordinate-uncertainty-meters": { + "description": "The average/static uncertainty of coordinates in this dataset, given in meters. Computed e.g. as the standard deviation of coordinate corrections during smoothing / splining.", + "type": "number", + "minimum": 0 + }, + "image-context": { + "description": "The overarching project context within which the image set was created", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the context" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the context" + } + }, + "required": [ + "name" + ] + }, + "image-project": { + "description": "The more specific project or expedition or cruise or experiment or ... within which the image set was created.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the project" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the project" + } + }, + "required": [ + "name" + ] + }, + "image-event": { + "description": "One event of a project or expedition or cruise or experiment or ... that led to the creation of this image set.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the event" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the event" + } + }, + "required": [ + "name" + ] + }, + "image-platform": { + "description": "A URI pointing to a description of the camera platform used to create this image set", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the platform" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the platform" + } + }, + "required": [ + "name" + ] + }, + "image-sensor": { + "description": "A URI pointing to a description of the sensor used to create this image set.", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the sensor" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the sensor" + } + }, + "required": [ + "name" + ] + }, + "image-uuid": { + "description": "A (random) UUID for the individual image file (still or moving). This UUID needs to be embedded within the image files. For still images in the exif tag 'ImageUniqueID', for videos in the XMP tag 'identifier' in the Dublin Core namespace. For Matroska video containers the first 'Segment UID' is used.", + "type": "string", + "format": "uuid" + }, + "image-hash-sha256": { + "description": "An SHA256 hash to represent the whole file (including UUID in file metadata header!) to verify integrity on disk", + "type": "string", + "minLength": 64, + "maxLength": 64 + }, + "image-pi": { + "description": "Information to identify the principal investigator", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the PI" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the PI. Could be ORCID URI" + } + }, + "required": [ + "name" + ] + }, + "image-creators": { + "description": "A list containing dicts for all creators containing:", + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the creator" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the creator. Could be ORCID URI" + } + }, + "required": [ + "name" + ] + } + }, + "image-license": { + "description": "A URL pointing to the license to use the data (should be FAIR, e.g. **CC-BY** or CC-0)", + "type": "object", + "properties": { + "name": { + "type": "string", + "anyOf": [ + { + "const": "CC-0", + "description": "No Rights Reserved" + }, + { + "const": "CC-BY", + "description": "Credit must be given to the creator." + }, + {} + ], + "description": "The name of the license" + }, + "uri": { + "type": "string", + "format": "uri", + "description": "A URI pointing to details of the license" + } + }, + "required": [ + "name" + ] + }, + "image-copyright": { + "description": "Copyright statement or contact person or office", + "type": "string" + }, + "image-abstract": { + "description": "500 - 2000 characters describing what, when, where, why and how the data was collected. Includes general information on the event (aka station, experiment), e.g. overlap between images/frames, parameters on platform movement, aims, purpose of image capture etc.", + "type": "string" + }, + "image-set-local-path": { + "description": "Local relative or absolute path to a directory in which (also its sub-directories), the referenced image files are located. Absolute paths must start with and relative paths without path separator (ignoring drive letters on windows). The default is the relative path `../raw`.", + "type": "string" + } + }, + "@context": [ + { + "DarwinCore": "https://rs.tdwg.org/dwc/terms/", + "image-set-name": "DarwinCore:datasetName", + "image-set-uuid": "DarwinCore:datasetID", + "image-datetime": "DarwinCore:eventData", + "image-latitude": "DarwinCore:decimalLatitude", + "image-longitude": "DarwinCore:decimalLongitude", + "image-altitude-meters": "DarwinCore:verbatimElevation", + "image-coordinate-reference-system": "DarwinCore:verbatimSRS", + "image-coordinate-uncertainty-meters": "DarwinCore:coordinatePrecision", + "image-uuid": "DarwinCore:eventID", + "image-creators": "DarwinCore:rightsHolder", + "image-license": "DarwinCore:license", + "image-acquisition": "DarwinCore:type" + }, + { + "AudiovisualCore": "https://rs.tdwg.org/ac/terms/", + "image-set-handle": "AudiovisualCore:accessURI", + "image-datetime": "AudiovisualCore:startTime", + "image-sensor": "AudiovisualCore:captureDevice", + "image-hash-sha256": "AudiovisualCore:hashValue" + }, + { + "@vocab": "https://schema.org", + "image-set-name": "name", + "image-set-uuid": "identifier", + "image-datetime": "dateCreated", + "image-project": "isPartOf", + "image-creators": "creator", + "image-license": "license", + "image-acquisition": "ImageObject" + } + ] +} \ No newline at end of file diff --git a/standard/schema/ifdo.json b/standard/schema/ifdo.json new file mode 100644 index 0000000000000000000000000000000000000000..42ddc6e717e36a405dcd711a879014ec6bd6ec3e --- /dev/null +++ b/standard/schema/ifdo.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/ifdo.json", + "title": "image FAIR Digital Object", + "description": "An iFDO file is a human- and machine-readable file format collecting metadata of an entire image set, without including the actual image data, only references to it through persistent identifiers.", + "type": "object", + "$defs": { + "iFDO-fields": { + "anyOf": [ + {"$ref": "https://marine-imaging.com/fair/schemas/ifdo-core.json"}, + {"$ref": "https://marine-imaging.com/fair/schemas/ifdo-capture.json"}, + {"$ref": "https://marine-imaging.com/fair/schemas/ifdo-content.json"} + ], + "unevaluatedProperties": false + }, + "image-item-core": { + "type": "object", + "$ref": "#/$defs/iFDO-fields", + "required": ["image-uuid","image-hash-sha256","image-handle"] + } + }, + "properties": { + "image-set-header": { + "description": "The default settings for all fields. Can be overwritten by metadata in the image-set-items field", + "$ref": "#/$defs/iFDO-fields", + "required": [ + "image-set-name", + "image-set-uuid", + "image-set-handle", + "image-set-ifdo-version", + "image-datetime", + "image-latitude", + "image-longitude", + "image-altitude-meters", + "image-coordinate-reference-system", + "image-coordinate-uncertainty-meters", + "image-context", + "image-project", + "image-event", + "image-platform", + "image-sensor", + "image-pi", + "image-creators", + "image-license", + "image-copyright", + "image-abstract" + ] + }, + "image-set-items": { + "description": "The detailed metadata information for individual images.", + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/$defs/image-item-core" + }, + { + "type": "array", + "description": "The metadata information for videos with metadata varying in time.", + "prefixItems":[{ + "$ref": "#/$defs/image-item-core", + "description": "The common metadata information in the first entry of videos with metadata varying in time." + }], + "items": { + "type": "object", + "description": "A video's metadata information for a specific point in time", + "$ref": "#/$defs/iFDO-fields", + "required": ["image-datetime"] + } + } + ] + } + } + }, + "required": ["image-set-header","image-set-items"] +} + + + diff --git a/standard/schema/provenance.json b/standard/schema/provenance.json new file mode 100644 index 0000000000000000000000000000000000000000..57248ec188fda3e146e62a8c59ee2928835a8be3 --- /dev/null +++ b/standard/schema/provenance.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://marine-imaging.com/fair/schemas/provenance.json", + "title": "Documenting a processing workflow", + "description": "A schema to document the agents, activities and entities that led to an image set entity", + "type": "object", + "properties": { + "provenance-agents": { + "type": "array", + "description": "A list of all the agents in this provenance documentation", + "items": { + "$ref": "#/$defs/agent" + } + }, + "provenance-entities": { + "type": "array", + "description": "A list of all the entities in this provenance documentation", + "items": { + "$ref": "#/$defs/entity" + } + }, + "provenance-activities": { + "type": "array", + "description": "A list of all the activities in this provenance documentation", + "items": { + "$ref": "#/$defs/activity" + } + } + }, + "$defs": { + "agent": { + "type": "object", + "description": "Someone or something that operates, takes responsibility, conducts, etc.", + "properties": { + "name": { + "type": "string", + "description": "A human-readable identifier of the agent" + }, + "id": { + "type": "string", + "description": "A unique identifier for the agent. Could be a uri." + } + } + }, + "entity": { + "type": "object", + "description": "A static instance of a virtual thing", + "properties": { + "name": { + "type": "string", + "description": "A human-readable identifier of the entity" + }, + "id": { + "type": "string", + "description": "A unique identifier for the entity. Could be a uri." + }, + "created-at": { + "type": "string", + "format": "date-time", + "description": "The time at which this entity was created in its entirety" + }, + "attributed-to": { + "type": "array", + "description": "A list of agents that relate to this entity", + "items": { + "$ref": "#/$defs/agent" + } + }, + "generated-by": { + "type": "array", + "description": "A list of activities that created this entity", + "items": { + "$ref": "#/$defs/activity" + } + } + } + }, + "activity": { + "type": "object", + "description": "A process that works with entities and is operated by agents", + "properties": { + "start-time": { + "type": "string", + "format": "date-time", + "description": "The time at which the activity began" + }, + "end-time": { + "type": "string", + "format": "date-time", + "description": "The time at which the activity ended" + }, + "associated-agents": { + "type": "array", + "description": "The agents that are associated to this activity", + "items": { + "$ref": "#/$defs/agent" + } + }, + "used-entities": { + "type": "array", + "description": "The entities that are associated to this activity", + "items": { + "$ref": "#/$defs/entity" + } + } + } + } + } +} diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000000000000000000000000000000000000..c2239b0a90b05411b68cf3bed0cf69bab67b03cc --- /dev/null +++ b/uv.lock @@ -0,0 +1,1025 @@ +version = 1 +requires-python = ">=3.12" + +[[package]] +name = "argcomplete" +version = "3.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/be/6c23d80cb966fb8f83fb1ebfb988351ae6b0554d0c3a613ee4531c026597/argcomplete-3.5.3.tar.gz", hash = "sha256:c12bf50eded8aebb298c7b7da7a5ff3ee24dffd9f5281867dfe1424b58c55392", size = 72999 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/08/2a4db06ec3d203124c967fc89295e85a202e5cbbcdc08fd6a64b65217d1e/argcomplete-3.5.3-py3-none-any.whl", hash = "sha256:2ab2c4a215c59fd6caaff41a869480a23e8f6a5f910b266c1808037f4e375b61", size = 43569 }, +] + +[[package]] +name = "attrs" +version = "24.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, +] + +[[package]] +name = "babel" +version = "2.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, +] + +[[package]] +name = "brotli" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/c2/f9e977608bdf958650638c3f1e28f85a1b075f075ebbe77db8555463787b/Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", size = 7372270 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/d0/5373ae13b93fe00095a58efcbce837fd470ca39f703a235d2a999baadfbc/Brotli-1.1.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", size = 815693 }, + { url = "https://files.pythonhosted.org/packages/8e/48/f6e1cdf86751300c288c1459724bfa6917a80e30dbfc326f92cea5d3683a/Brotli-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", size = 422489 }, + { url = "https://files.pythonhosted.org/packages/06/88/564958cedce636d0f1bed313381dfc4b4e3d3f6015a63dae6146e1b8c65c/Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", size = 873081 }, + { url = "https://files.pythonhosted.org/packages/58/79/b7026a8bb65da9a6bb7d14329fd2bd48d2b7f86d7329d5cc8ddc6a90526f/Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", size = 446244 }, + { url = "https://files.pythonhosted.org/packages/e5/18/c18c32ecea41b6c0004e15606e274006366fe19436b6adccc1ae7b2e50c2/Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", size = 2906505 }, + { url = "https://files.pythonhosted.org/packages/08/c8/69ec0496b1ada7569b62d85893d928e865df29b90736558d6c98c2031208/Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", size = 2944152 }, + { url = "https://files.pythonhosted.org/packages/ab/fb/0517cea182219d6768113a38167ef6d4eb157a033178cc938033a552ed6d/Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", size = 2919252 }, + { url = "https://files.pythonhosted.org/packages/c7/53/73a3431662e33ae61a5c80b1b9d2d18f58dfa910ae8dd696e57d39f1a2f5/Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", size = 2845955 }, + { url = "https://files.pythonhosted.org/packages/55/ac/bd280708d9c5ebdbf9de01459e625a3e3803cce0784f47d633562cf40e83/Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", size = 2914304 }, + { url = "https://files.pythonhosted.org/packages/76/58/5c391b41ecfc4527d2cc3350719b02e87cb424ef8ba2023fb662f9bf743c/Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", size = 2814452 }, + { url = "https://files.pythonhosted.org/packages/c7/4e/91b8256dfe99c407f174924b65a01f5305e303f486cc7a2e8a5d43c8bec3/Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", size = 2938751 }, + { url = "https://files.pythonhosted.org/packages/5a/a6/e2a39a5d3b412938362bbbeba5af904092bf3f95b867b4a3eb856104074e/Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", size = 2933757 }, + { url = "https://files.pythonhosted.org/packages/13/f0/358354786280a509482e0e77c1a5459e439766597d280f28cb097642fc26/Brotli-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", size = 2936146 }, + { url = "https://files.pythonhosted.org/packages/80/f7/daf538c1060d3a88266b80ecc1d1c98b79553b3f117a485653f17070ea2a/Brotli-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", size = 2848055 }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0eaa0585c4077d3c2d1edf322d8e97aabf317941d3a72d7b3ad8bce004b0/Brotli-1.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", size = 3035102 }, + { url = "https://files.pythonhosted.org/packages/d8/63/1c1585b2aa554fe6dbce30f0c18bdbc877fa9a1bf5ff17677d9cca0ac122/Brotli-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", size = 2930029 }, + { url = "https://files.pythonhosted.org/packages/5f/3b/4e3fd1893eb3bbfef8e5a80d4508bec17a57bb92d586c85c12d28666bb13/Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", size = 333276 }, + { url = "https://files.pythonhosted.org/packages/3d/d5/942051b45a9e883b5b6e98c041698b1eb2012d25e5948c58d6bf85b1bb43/Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", size = 357255 }, + { url = "https://files.pythonhosted.org/packages/0a/9f/fb37bb8ffc52a8da37b1c03c459a8cd55df7a57bdccd8831d500e994a0ca/Brotli-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", size = 815681 }, + { url = "https://files.pythonhosted.org/packages/06/b3/dbd332a988586fefb0aa49c779f59f47cae76855c2d00f450364bb574cac/Brotli-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", size = 422475 }, + { url = "https://files.pythonhosted.org/packages/bb/80/6aaddc2f63dbcf2d93c2d204e49c11a9ec93a8c7c63261e2b4bd35198283/Brotli-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", size = 2906173 }, + { url = "https://files.pythonhosted.org/packages/ea/1d/e6ca79c96ff5b641df6097d299347507d39a9604bde8915e76bf026d6c77/Brotli-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648", size = 2943803 }, + { url = "https://files.pythonhosted.org/packages/ac/a3/d98d2472e0130b7dd3acdbb7f390d478123dbf62b7d32bda5c830a96116d/Brotli-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0", size = 2918946 }, + { url = "https://files.pythonhosted.org/packages/c4/a5/c69e6d272aee3e1423ed005d8915a7eaa0384c7de503da987f2d224d0721/Brotli-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089", size = 2845707 }, + { url = "https://files.pythonhosted.org/packages/58/9f/4149d38b52725afa39067350696c09526de0125ebfbaab5acc5af28b42ea/Brotli-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368", size = 2936231 }, + { url = "https://files.pythonhosted.org/packages/5a/5a/145de884285611838a16bebfdb060c231c52b8f84dfbe52b852a15780386/Brotli-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c", size = 2848157 }, + { url = "https://files.pythonhosted.org/packages/50/ae/408b6bfb8525dadebd3b3dd5b19d631da4f7d46420321db44cd99dcf2f2c/Brotli-1.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284", size = 3035122 }, + { url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206 }, + { url = "https://files.pythonhosted.org/packages/c2/f0/a61d9262cd01351df22e57ad7c34f66794709acab13f34be2675f45bf89d/Brotli-1.1.0-cp313-cp313-win32.whl", hash = "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0", size = 333804 }, + { url = "https://files.pythonhosted.org/packages/7e/c1/ec214e9c94000d1c1974ec67ced1c970c148aa6b8d8373066123fc3dbf06/Brotli-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", size = 358517 }, +] + +[[package]] +name = "brotlicffi" +version = "1.1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/9d/70caa61192f570fcf0352766331b735afa931b4c6bc9a348a0925cc13288/brotlicffi-1.1.0.0.tar.gz", hash = "sha256:b77827a689905143f87915310b93b273ab17888fd43ef350d4832c4a71083c13", size = 465192 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/11/7b96009d3dcc2c931e828ce1e157f03824a69fb728d06bfd7b2fc6f93718/brotlicffi-1.1.0.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9b7ae6bd1a3f0df532b6d67ff674099a96d22bc0948955cb338488c31bfb8851", size = 453786 }, + { url = "https://files.pythonhosted.org/packages/d6/e6/a8f46f4a4ee7856fbd6ac0c6fb0dc65ed181ba46cd77875b8d9bbe494d9e/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19ffc919fa4fc6ace69286e0a23b3789b4219058313cf9b45625016bf7ff996b", size = 2911165 }, + { url = "https://files.pythonhosted.org/packages/be/20/201559dff14e83ba345a5ec03335607e47467b6633c210607e693aefac40/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9feb210d932ffe7798ee62e6145d3a757eb6233aa9a4e7db78dd3690d7755814", size = 2927895 }, + { url = "https://files.pythonhosted.org/packages/cd/15/695b1409264143be3c933f708a3f81d53c4a1e1ebbc06f46331decbf6563/brotlicffi-1.1.0.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84763dbdef5dd5c24b75597a77e1b30c66604725707565188ba54bab4f114820", size = 2851834 }, + { url = "https://files.pythonhosted.org/packages/b4/40/b961a702463b6005baf952794c2e9e0099bde657d0d7e007f923883b907f/brotlicffi-1.1.0.0-cp37-abi3-win32.whl", hash = "sha256:1b12b50e07c3911e1efa3a8971543e7648100713d4e0971b13631cce22c587eb", size = 341731 }, + { url = "https://files.pythonhosted.org/packages/1c/fa/5408a03c041114ceab628ce21766a4ea882aa6f6f0a800e04ee3a30ec6b9/brotlicffi-1.1.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:994a4f0681bb6c6c3b0925530a1926b7a189d878e6e5e38fae8efa47c5d9c613", size = 366783 }, +] + +[[package]] +name = "certifi" +version = "2024.12.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, + { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, + { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, + { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, + { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, + { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, + { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, + { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, + { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, + { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, + { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, + { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, + { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "colorlog" +version = "6.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d3/7a/359f4d5df2353f26172b3cc39ea32daa39af8de522205f512f458923e677/colorlog-6.9.0.tar.gz", hash = "sha256:bfba54a1b93b94f54e1f4fe48395725a3d92fd2a4af702f6bd70946bdc0c6ac2", size = 16624 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/51/9b208e85196941db2f0654ad0357ca6388ab3ed67efdbfc799f35d1f83aa/colorlog-6.9.0-py3-none-any.whl", hash = "sha256:5906e71acd67cb07a71e779c47c4bcb45fb8c2993eebe9e5adcd6a6f1b283eff", size = 11424 }, +] + +[[package]] +name = "cssselect2" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tinycss2" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/fc/326cb6f988905998f09bb54a3f5d98d4462ba119363c0dfad29750d48c09/cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a", size = 35888 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/3a/e39436efe51894243ff145a37c4f9a030839b97779ebcc4f13b3ba21c54e/cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969", size = 15586 }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, +] + +[[package]] +name = "fair-marine-images" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "gitpython" }, + { name = "jsonschema" }, + { name = "mkdocs" }, + { name = "mkdocs-build-plantuml-plugin" }, + { name = "mkdocs-macros-plugin" }, + { name = "mkdocs-material" }, + { name = "nox" }, + { name = "pyyaml" }, + { name = "weasyprint" }, +] + +[package.metadata] +requires-dist = [ + { name = "gitpython", specifier = ">=3.1.44" }, + { name = "jsonschema", specifier = ">=4.23.0" }, + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-build-plantuml-plugin", specifier = ">=1.9.0" }, + { name = "mkdocs-macros-plugin", specifier = ">=1.3.7" }, + { name = "mkdocs-material", specifier = ">=9.5.49" }, + { name = "nox", specifier = ">=2024.10.9" }, + { name = "pyyaml", specifier = ">=6.0.2" }, + { name = "weasyprint", specifier = ">=63.1" }, +] + +[[package]] +name = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, +] + +[[package]] +name = "fonttools" +version = "4.55.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/61/a300d1574dc381393424047c0396a0e213db212e28361123af9830d71a8d/fonttools-4.55.3.tar.gz", hash = "sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45", size = 3498155 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/58/fbcf5dff7e3ea844bb00c4d806ca1e339e1f2dce5529633bf4842c0c9a1f/fonttools-4.55.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35", size = 2765380 }, + { url = "https://files.pythonhosted.org/packages/81/dd/da6e329e51919b4f421c8738f3497e2ab08c168e76aaef7b6d5351862bdf/fonttools-4.55.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c", size = 2297940 }, + { url = "https://files.pythonhosted.org/packages/00/44/f5ee560858425c99ef07e04919e736db09d6416408e5a8d3bbfb4a6623fd/fonttools-4.55.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7", size = 4793327 }, + { url = "https://files.pythonhosted.org/packages/24/da/0a001926d791c55e29ac3c52964957a20dbc1963615446b568b7432891c3/fonttools-4.55.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314", size = 4865624 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/1edd8b13a427a9fb6418373437caa586c0caa57f260af8e0548f4d11e340/fonttools-4.55.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427", size = 4774166 }, + { url = "https://files.pythonhosted.org/packages/9c/ec/ade054097976c3d6debc9032e09a351505a0196aa5493edf021be376f75e/fonttools-4.55.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a", size = 5001832 }, + { url = "https://files.pythonhosted.org/packages/e2/cd/233f0e31ad799bb91fc78099c8b4e5ec43b85a131688519640d6bae46f6a/fonttools-4.55.3-cp312-cp312-win32.whl", hash = "sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07", size = 2162228 }, + { url = "https://files.pythonhosted.org/packages/46/45/a498b5291f6c0d91b2394b1ed7447442a57d1c9b9cf8f439aee3c316a56e/fonttools-4.55.3-cp312-cp312-win_amd64.whl", hash = "sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54", size = 2209118 }, + { url = "https://files.pythonhosted.org/packages/9c/9f/00142a19bad96eeeb1aed93f567adc19b7f2c1af6f5bc0a1c3de90b4b1ac/fonttools-4.55.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a430178ad3e650e695167cb53242dae3477b35c95bef6525b074d87493c4bf29", size = 2752812 }, + { url = "https://files.pythonhosted.org/packages/b0/20/14b8250d63ba65e162091fb0dda07730f90c303bbf5257e9ddacec7230d9/fonttools-4.55.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:529cef2ce91dc44f8e407cc567fae6e49a1786f2fefefa73a294704c415322a4", size = 2291521 }, + { url = "https://files.pythonhosted.org/packages/34/47/a681cfd10245eb74f65e491a934053ec75c4af639655446558f29818e45e/fonttools-4.55.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e75f12c82127486fac2d8bfbf5bf058202f54bf4f158d367e41647b972342ca", size = 4770980 }, + { url = "https://files.pythonhosted.org/packages/d2/6c/a7066afc19db0705a12efd812e19c32cde2b9514eb714659522f2ebd60b6/fonttools-4.55.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:859c358ebf41db18fb72342d3080bce67c02b39e86b9fbcf1610cca14984841b", size = 4845534 }, + { url = "https://files.pythonhosted.org/packages/0c/a2/3c204fbabbfd845d9bdcab9ae35279d41e9a4bf5c80a0a2708f9c5a195d6/fonttools-4.55.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:546565028e244a701f73df6d8dd6be489d01617863ec0c6a42fa25bf45d43048", size = 4753910 }, + { url = "https://files.pythonhosted.org/packages/6e/8c/b4cb3592880340b89e4ef6601b531780bba73862332a6451d78fe135d6cb/fonttools-4.55.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aca318b77f23523309eec4475d1fbbb00a6b133eb766a8bdc401faba91261abe", size = 4976411 }, + { url = "https://files.pythonhosted.org/packages/fc/a8/4bf98840ff89fcc188470b59daec57322178bf36d2f4f756cd19a42a826b/fonttools-4.55.3-cp313-cp313-win32.whl", hash = "sha256:8c5ec45428edaa7022f1c949a632a6f298edc7b481312fc7dc258921e9399628", size = 2160178 }, + { url = "https://files.pythonhosted.org/packages/e6/57/4cc35004605416df3225ff362f3455cf09765db00df578ae9e46d0fefd23/fonttools-4.55.3-cp313-cp313-win_amd64.whl", hash = "sha256:11e5de1ee0d95af4ae23c1a138b184b7f06e0b6abacabf1d0db41c90b03d834b", size = 2206102 }, + { url = "https://files.pythonhosted.org/packages/99/3b/406d17b1f63e04a82aa621936e6e1c53a8c05458abd66300ac85ea7f9ae9/fonttools-4.55.3-py3-none-any.whl", hash = "sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977", size = 1111638 }, +] + +[package.optional-dependencies] +woff = [ + { name = "brotli", marker = "platform_python_implementation == 'CPython'" }, + { name = "brotlicffi", marker = "platform_python_implementation != 'CPython'" }, + { name = "zopfli" }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 }, +] + +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, +] + +[[package]] +name = "gitpython" +version = "3.1.44" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599 }, +] + +[[package]] +name = "hjson" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/e5/0b56d723a76ca67abadbf7fb71609fb0ea7e6926e94fcca6c65a85b36a0e/hjson-3.1.0.tar.gz", hash = "sha256:55af475a27cf83a7969c808399d7bccdec8fb836a07ddbd574587593b9cdcf75", size = 40541 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/7f/13cd798d180af4bf4c0ceddeefba2b864a63c71645abc0308b768d67bb81/hjson-3.1.0-py3-none-any.whl", hash = "sha256:65713cdcf13214fb554eb8b4ef803419733f4f5e551047c9b711098ab7186b89", size = 54018 }, +] + +[[package]] +name = "httplib2" +version = "0.22.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/ad/2371116b22d616c194aa25ec410c9c6c37f23599dcd590502b74db197584/httplib2-0.22.0.tar.gz", hash = "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81", size = 351116 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/6c/d2fbdaaa5959339d53ba38e94c123e4e84b8fbc4b84beb0e70d7c1608486/httplib2-0.22.0-py3-none-any.whl", hash = "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", size = 96854 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "jinja2" +version = "3.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, +] + +[[package]] +name = "jsonschema" +version = "4.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2024.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, + { 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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 }, +] + +[[package]] +name = "mkdocs-build-plantuml-plugin" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httplib2" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/09/e2a651a1b98aa2685b8dcd1c8b65e6082254e584d51c9f9cddfb86223159/mkdocs-build-plantuml-plugin-1.9.0.tar.gz", hash = "sha256:b0468a2024741ff5c39d5307e34e54e11225ee0da378ef2bc35ed0e0f1cfc99d", size = 8728 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/2d/31e3941ccc1cb7acb5df12f536658b03e07c0f44ace7067f5e71aedd0189/mkdocs_build_plantuml_plugin-1.9.0-py3-none-any.whl", hash = "sha256:ba738b698b69dfba8fbd49f92336a17cbe9df16c7b4d384b85528058301ec0c3", size = 9129 }, +] + +[[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 } +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 }, +] + +[[package]] +name = "mkdocs-macros-plugin" +version = "1.3.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hjson" }, + { name = "jinja2" }, + { name = "mkdocs" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "super-collections" }, + { name = "termcolor" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/65/61a746c56788867221aebf07fe4b6b4c08ac99cf341fd51d728c89d1456e/mkdocs_macros_plugin-1.3.7.tar.gz", hash = "sha256:17c7fd1a49b94defcdb502fd453d17a1e730f8836523379d21292eb2be4cb523", size = 33466 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/cf/f03331298ee50a4da6fb72ccec79078041158c1f8b5fc24835c1be42232e/mkdocs_macros_plugin-1.3.7-py3-none-any.whl", hash = "sha256:02432033a5b77fb247d6ec7924e72fc4ceec264165b1644ab8d0dc159c22ce59", size = 37799 }, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.49" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/14/8daeeecee2e25bd84239a843fdcb92b20db88ebbcb26e0d32f414ca54a22/mkdocs_material-9.5.49.tar.gz", hash = "sha256:3671bb282b4f53a1c72e08adbe04d2481a98f85fed392530051f80ff94a9621d", size = 3949559 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/2d/2dd23a36b48421db54f118bb6f6f733dbe2d5c78fe7867375e48649fd3df/mkdocs_material-9.5.49-py3-none-any.whl", hash = "sha256:c3c2d8176b18198435d3a3e119011922f3e11424074645c24019c2dcf08a360e", size = 8684098 }, +] + +[[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 } +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 }, +] + +[[package]] +name = "nox" +version = "2024.10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "colorlog" }, + { name = "packaging" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/93/4df547afcd56e0b2bbaa99bc2637deb218a01802ed62d80f763189be802c/nox-2024.10.9.tar.gz", hash = "sha256:7aa9dc8d1c27e9f45ab046ffd1c3b2c4f7c91755304769df231308849ebded95", size = 4003197 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/00/981f0dcaddf111b6caf6e03d7f7f01b07fd4af117316a7eb1c22039d9e37/nox-2024.10.9-py3-none-any.whl", hash = "sha256:1d36f309a0a2a853e9bccb76bbef6bb118ba92fa92674d15604ca99adeb29eab", size = 61210 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 }, +] + +[[package]] +name = "pillow" +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/20/9ce6ed62c91c073fcaa23d216e68289e19d95fb8188b9fb7a63d36771db8/pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a", size = 3226818 }, + { url = "https://files.pythonhosted.org/packages/b9/d8/f6004d98579a2596c098d1e30d10b248798cceff82d2b77aa914875bfea1/pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b", size = 3101662 }, + { url = "https://files.pythonhosted.org/packages/08/d9/892e705f90051c7a2574d9f24579c9e100c828700d78a63239676f960b74/pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3", size = 4329317 }, + { url = "https://files.pythonhosted.org/packages/8c/aa/7f29711f26680eab0bcd3ecdd6d23ed6bce180d82e3f6380fb7ae35fcf3b/pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a", size = 4412999 }, + { url = "https://files.pythonhosted.org/packages/c8/c4/8f0fe3b9e0f7196f6d0bbb151f9fba323d72a41da068610c4c960b16632a/pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1", size = 4368819 }, + { url = "https://files.pythonhosted.org/packages/38/0d/84200ed6a871ce386ddc82904bfadc0c6b28b0c0ec78176871a4679e40b3/pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f", size = 4496081 }, + { url = "https://files.pythonhosted.org/packages/84/9c/9bcd66f714d7e25b64118e3952d52841a4babc6d97b6d28e2261c52045d4/pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91", size = 4296513 }, + { url = "https://files.pythonhosted.org/packages/db/61/ada2a226e22da011b45f7104c95ebda1b63dcbb0c378ad0f7c2a710f8fd2/pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c", size = 4431298 }, + { url = "https://files.pythonhosted.org/packages/e7/c4/fc6e86750523f367923522014b821c11ebc5ad402e659d8c9d09b3c9d70c/pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6", size = 2291630 }, + { url = "https://files.pythonhosted.org/packages/08/5c/2104299949b9d504baf3f4d35f73dbd14ef31bbd1ddc2c1b66a5b7dfda44/pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf", size = 2626369 }, + { url = "https://files.pythonhosted.org/packages/37/f3/9b18362206b244167c958984b57c7f70a0289bfb59a530dd8af5f699b910/pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5", size = 2375240 }, + { url = "https://files.pythonhosted.org/packages/b3/31/9ca79cafdce364fd5c980cd3416c20ce1bebd235b470d262f9d24d810184/pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc", size = 3226640 }, + { url = "https://files.pythonhosted.org/packages/ac/0f/ff07ad45a1f172a497aa393b13a9d81a32e1477ef0e869d030e3c1532521/pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0", size = 3101437 }, + { url = "https://files.pythonhosted.org/packages/08/2f/9906fca87a68d29ec4530be1f893149e0cb64a86d1f9f70a7cfcdfe8ae44/pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1", size = 4326605 }, + { url = "https://files.pythonhosted.org/packages/b0/0f/f3547ee15b145bc5c8b336401b2d4c9d9da67da9dcb572d7c0d4103d2c69/pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec", size = 4411173 }, + { url = "https://files.pythonhosted.org/packages/b1/df/bf8176aa5db515c5de584c5e00df9bab0713548fd780c82a86cba2c2fedb/pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5", size = 4369145 }, + { url = "https://files.pythonhosted.org/packages/de/7c/7433122d1cfadc740f577cb55526fdc39129a648ac65ce64db2eb7209277/pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114", size = 4496340 }, + { url = "https://files.pythonhosted.org/packages/25/46/dd94b93ca6bd555588835f2504bd90c00d5438fe131cf01cfa0c5131a19d/pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352", size = 4296906 }, + { url = "https://files.pythonhosted.org/packages/a8/28/2f9d32014dfc7753e586db9add35b8a41b7a3b46540e965cb6d6bc607bd2/pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3", size = 4431759 }, + { url = "https://files.pythonhosted.org/packages/33/48/19c2cbe7403870fbe8b7737d19eb013f46299cdfe4501573367f6396c775/pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9", size = 2291657 }, + { url = "https://files.pythonhosted.org/packages/3b/ad/285c556747d34c399f332ba7c1a595ba245796ef3e22eae190f5364bb62b/pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c", size = 2626304 }, + { url = "https://files.pythonhosted.org/packages/e5/7b/ef35a71163bf36db06e9c8729608f78dedf032fc8313d19bd4be5c2588f3/pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65", size = 2375117 }, + { url = "https://files.pythonhosted.org/packages/79/30/77f54228401e84d6791354888549b45824ab0ffde659bafa67956303a09f/pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861", size = 3230060 }, + { url = "https://files.pythonhosted.org/packages/ce/b1/56723b74b07dd64c1010fee011951ea9c35a43d8020acd03111f14298225/pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081", size = 3106192 }, + { url = "https://files.pythonhosted.org/packages/e1/cd/7bf7180e08f80a4dcc6b4c3a0aa9e0b0ae57168562726a05dc8aa8fa66b0/pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c", size = 4446805 }, + { url = "https://files.pythonhosted.org/packages/97/42/87c856ea30c8ed97e8efbe672b58c8304dee0573f8c7cab62ae9e31db6ae/pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547", size = 4530623 }, + { url = "https://files.pythonhosted.org/packages/ff/41/026879e90c84a88e33fb00cc6bd915ac2743c67e87a18f80270dfe3c2041/pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab", size = 4465191 }, + { url = "https://files.pythonhosted.org/packages/e5/fb/a7960e838bc5df57a2ce23183bfd2290d97c33028b96bde332a9057834d3/pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9", size = 2295494 }, + { url = "https://files.pythonhosted.org/packages/d7/6c/6ec83ee2f6f0fda8d4cf89045c6be4b0373ebfc363ba8538f8c999f63fcd/pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe", size = 2631595 }, + { url = "https://files.pythonhosted.org/packages/cf/6c/41c21c6c8af92b9fea313aa47c75de49e2f9a467964ee33eb0135d47eb64/pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756", size = 2377651 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pydyf" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/c2/97fc6ce4ce0045080dc99446def812081b57750ed8aa67bfdfafa4561fe5/pydyf-0.11.0.tar.gz", hash = "sha256:394dddf619cca9d0c55715e3c55ea121a9bf9cbc780cdc1201a2427917b86b64", size = 17769 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/ac/d5db977deaf28c6ecbc61bbca269eb3e8f0b3a1f55c8549e5333e606e005/pydyf-0.11.0-py3-none-any.whl", hash = "sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3", size = 8104 }, +] + +[[package]] +name = "pygments" +version = "2.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/96/b4337b778d2e9e77541a8d1cab00989aaeb1d6003c891cdc89221bd25651/pymdown_extensions-10.14.tar.gz", hash = "sha256:741bd7c4ff961ba40b7528d32284c53bc436b8b1645e8e37c3e57770b8700a34", size = 844927 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/ae/55d347eda5a4c57a2a042fe2e7616d14981115f566b9f8f69901aba3c0c6/pymdown_extensions-10.14-py3-none-any.whl", hash = "sha256:202481f716cc8250e4be8fce997781ebf7917701b59652458ee47f2401f818b5", size = 264264 }, +] + +[[package]] +name = "pyparsing" +version = "3.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/1a/3544f4f299a47911c2ab3710f534e52fea62a633c96806995da5d25be4b2/pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a", size = 1067694 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/a7/c8a2d361bf89c0d9577c934ebb7421b25dc84bf3a8e3ac0a40aed9acc547/pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", size = 107716 }, +] + +[[package]] +name = "pyphen" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/46/3dd0ae4b52016496069af6c4fca3b5918b0281fc92678f739edb8f3eb377/pyphen-0.17.0.tar.gz", hash = "sha256:1d13acd1ce37a384d7612954ae6c7801bb4c5316da0e2b937b2127ba702a3da4", size = 2072773 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/ae/7919394672be4884ac8434e30be143db689b29b6e7fa0dd8eb2037af0337/pyphen-0.17.0-py3-none-any.whl", hash = "sha256:dad0b2e4aa80f6d70bf06711b2da36c47a756b933c1d0c4cbbab40f643a5958c", size = 2073297 }, +] + +[[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 } +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 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 }, +] + +[[package]] +name = "referencing" +version = "0.35.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/73ca1f8e72fff6fa52119dbd185f73a907b1989428917b24cff660129b6d/referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", size = 62991 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de", size = 26684 }, +] + +[[package]] +name = "regex" +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "rpds-py" +version = "0.22.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 }, + { url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 }, + { url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 }, + { url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 }, + { url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 }, + { url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 }, + { url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 }, + { url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 }, + { url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 }, + { url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 }, + { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 }, + { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 }, + { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 }, + { url = "https://files.pythonhosted.org/packages/d0/bf/36d5cc1f2c609ae6e8bf0fc35949355ca9d8790eceb66e6385680c951e60/rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", size = 351657 }, + { url = "https://files.pythonhosted.org/packages/24/2a/f1e0fa124e300c26ea9382e59b2d582cba71cedd340f32d1447f4f29fa4e/rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", size = 341829 }, + { url = "https://files.pythonhosted.org/packages/cf/c2/0da1231dd16953845bed60d1a586fcd6b15ceaeb965f4d35cdc71f70f606/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", size = 384220 }, + { url = "https://files.pythonhosted.org/packages/c7/73/a4407f4e3a00a9d4b68c532bf2d873d6b562854a8eaff8faa6133b3588ec/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", size = 391009 }, + { url = "https://files.pythonhosted.org/packages/a9/c3/04b7353477ab360fe2563f5f0b176d2105982f97cd9ae80a9c5a18f1ae0f/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", size = 426989 }, + { url = "https://files.pythonhosted.org/packages/8d/e6/e4b85b722bcf11398e17d59c0f6049d19cd606d35363221951e6d625fcb0/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", size = 441544 }, + { url = "https://files.pythonhosted.org/packages/27/fc/403e65e56f65fff25f2973216974976d3f0a5c3f30e53758589b6dc9b79b/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", size = 385179 }, + { url = "https://files.pythonhosted.org/packages/57/9b/2be9ff9700d664d51fd96b33d6595791c496d2778cb0b2a634f048437a55/rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", size = 415103 }, + { url = "https://files.pythonhosted.org/packages/bb/a5/03c2ad8ca10994fcf22dd2150dd1d653bc974fa82d9a590494c84c10c641/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", size = 560916 }, + { url = "https://files.pythonhosted.org/packages/ba/2e/be4fdfc8b5b576e588782b56978c5b702c5a2307024120d8aeec1ab818f0/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", size = 587062 }, + { url = "https://files.pythonhosted.org/packages/67/e0/2034c221937709bf9c542603d25ad43a68b4b0a9a0c0b06a742f2756eb66/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", size = 555734 }, + { url = "https://files.pythonhosted.org/packages/ea/ce/240bae07b5401a22482b58e18cfbabaa392409b2797da60223cca10d7367/rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", size = 220663 }, + { url = "https://files.pythonhosted.org/packages/cb/f0/d330d08f51126330467edae2fa4efa5cec8923c87551a79299380fdea30d/rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", size = 235503 }, + { url = "https://files.pythonhosted.org/packages/f7/c4/dbe1cc03df013bf2feb5ad00615038050e7859f381e96fb5b7b4572cd814/rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", size = 347698 }, + { url = "https://files.pythonhosted.org/packages/a4/3a/684f66dd6b0f37499cad24cd1c0e523541fd768576fa5ce2d0a8799c3cba/rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", size = 337330 }, + { url = "https://files.pythonhosted.org/packages/82/eb/e022c08c2ce2e8f7683baa313476492c0e2c1ca97227fe8a75d9f0181e95/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", size = 380022 }, + { url = "https://files.pythonhosted.org/packages/e4/21/5a80e653e4c86aeb28eb4fea4add1f72e1787a3299687a9187105c3ee966/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", size = 390754 }, + { url = "https://files.pythonhosted.org/packages/37/a4/d320a04ae90f72d080b3d74597074e62be0a8ecad7d7321312dfe2dc5a6a/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", size = 423840 }, + { url = "https://files.pythonhosted.org/packages/87/70/674dc47d93db30a6624279284e5631be4c3a12a0340e8e4f349153546728/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", size = 438970 }, + { url = "https://files.pythonhosted.org/packages/3f/64/9500f4d66601d55cadd21e90784cfd5d5f4560e129d72e4339823129171c/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", size = 383146 }, + { url = "https://files.pythonhosted.org/packages/4d/45/630327addb1d17173adcf4af01336fd0ee030c04798027dfcb50106001e0/rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", size = 408294 }, + { url = "https://files.pythonhosted.org/packages/5f/ef/8efb3373cee54ea9d9980b772e5690a0c9e9214045a4e7fa35046e399fee/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", size = 556345 }, + { url = "https://files.pythonhosted.org/packages/54/01/151d3b9ef4925fc8f15bfb131086c12ec3c3d6dd4a4f7589c335bf8e85ba/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", size = 582292 }, + { url = "https://files.pythonhosted.org/packages/30/89/35fc7a6cdf3477d441c7aca5e9bbf5a14e0f25152aed7f63f4e0b141045d/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", size = 553855 }, + { url = "https://files.pythonhosted.org/packages/8f/e0/830c02b2457c4bd20a8c5bb394d31d81f57fbefce2dbdd2e31feff4f7003/rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", size = 219100 }, + { url = "https://files.pythonhosted.org/packages/f8/30/7ac943f69855c2db77407ae363484b915d861702dbba1aa82d68d57f42be/rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", size = 233794 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "smmap" +version = "5.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, +] + +[[package]] +name = "super-collections" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hjson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/05/d1b50919a0d206d77255217d96dea9ab34bd1eb965a21559380c48f9517e/super_collections-0.5.3.tar.gz", hash = "sha256:94c1ec96c0a0d5e8e7d389ed8cde6882ac246940507c5e6b86e91945c2968d46", size = 10178 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6d/58de58c521e7fb79bceb4da90d55250070bb4adfa3c870b82519a561c79d/super_collections-0.5.3-py3-none-any.whl", hash = "sha256:907d35b25dc4070910e8254bf2f5c928348af1cf8a1f1e8259e06c666e902cff", size = 8436 }, +] + +[[package]] +name = "termcolor" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/37/72/88311445fd44c455c7d553e61f95412cf89054308a1aa2434ab835075fc5/termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f", size = 13057 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/be/df630c387a0a054815d60be6a97eb4e8f17385d5d6fe660e1c02750062b4/termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8", size = 7755 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, +] + +[[package]] +name = "tinyhtml5" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/03/6111ed99e9bf7dfa1c30baeef0e0fb7e0bd387bd07f8e5b270776fe1de3f/tinyhtml5-2.0.0.tar.gz", hash = "sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc", size = 179507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/de/27c57899297163a4a84104d5cec0af3b1ac5faf62f44667e506373c6b8ce/tinyhtml5-2.0.0-py3-none-any.whl", hash = "sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e", size = 39793 }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +] + +[[package]] +name = "virtualenv" +version = "20.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/39/689abee4adc85aad2af8174bb195a819d0be064bf55fcc73b49d2b28ae77/virtualenv-20.28.1.tar.gz", hash = "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329", size = 7650532 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/8f/dfb257ca6b4e27cb990f1631142361e4712badab8e3ca8dc134d96111515/virtualenv-20.28.1-py3-none-any.whl", hash = "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", size = 4276719 }, +] + +[[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 } +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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { 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 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, +] + +[[package]] +name = "weasyprint" +version = "63.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, + { name = "cssselect2" }, + { name = "fonttools", extra = ["woff"] }, + { name = "pillow" }, + { name = "pydyf" }, + { name = "pyphen" }, + { name = "tinycss2" }, + { name = "tinyhtml5" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2b/f0/1ac7d241b8cabaaf047278ef67b64869473a4e0a2218a1cbc0a6ffb0d8fd/weasyprint-63.1.tar.gz", hash = "sha256:cb424e63e8dd3f14195bfe5f203527646aa40a2f00ac819f9d39b8304cec0044", size = 491880 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/39/9d63960b4545138d6c2c695795d77856e35f30d6e4bdc385c848c816d349/weasyprint-63.1-py3-none-any.whl", hash = "sha256:9d0319fe3ba553c9a77dc43a2d35b64a70c2b8809ad55a139a214803fde62bce", size = 299994 }, +] + +[[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 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, +] + +[[package]] +name = "zopfli" +version = "0.2.3.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/7c/a8f6696e694709e2abcbccd27d05ef761e9b6efae217e11d977471555b62/zopfli-0.2.3.post1.tar.gz", hash = "sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99", size = 175629 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/ce/b6441cc01881d06e0b5883f32c44e7cc9772e0d04e3e59277f59f80b9a19/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef", size = 295489 }, + { url = "https://files.pythonhosted.org/packages/93/f0/24dd708f00ae0a925bc5c9edae858641c80f6a81a516810dc4d21688a930/zopfli-0.2.3.post1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e", size = 163010 }, + { url = "https://files.pythonhosted.org/packages/65/57/0378eeeb5e3e1e83b1b0958616b2bf954f102ba5b0755b9747dafbd8cb72/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567", size = 823649 }, + { url = "https://files.pythonhosted.org/packages/ab/8a/3ab8a616d4655acf5cf63c40ca84e434289d7d95518a1a42d28b4a7228f8/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65", size = 826557 }, + { url = "https://files.pythonhosted.org/packages/ed/4d/7f6820af119c4fec6efaf007bffee7bc9052f695853a711a951be7afd26b/zopfli-0.2.3.post1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c", size = 851127 }, + { url = "https://files.pythonhosted.org/packages/e1/db/1ef5353ab06f9f2fb0c25ed0cddf1418fe275cc2ee548bc4a29340c44fe1/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df", size = 1754183 }, + { url = "https://files.pythonhosted.org/packages/39/03/44f8f39950354d330fa798e4bab1ac8e38ec787d3fde25d5b9c7770065a2/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8", size = 1905945 }, + { url = "https://files.pythonhosted.org/packages/74/7b/94b920c33cc64255f59e3cfc77c829b5c6e60805d189baeada728854a342/zopfli-0.2.3.post1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14", size = 1835885 }, + { url = "https://files.pythonhosted.org/packages/ad/89/c869ac844351e285a6165e2da79b715b0619a122e3160d183805adf8ab45/zopfli-0.2.3.post1-cp312-cp312-win32.whl", hash = "sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd", size = 82743 }, + { url = "https://files.pythonhosted.org/packages/29/e6/c98912fd3a589d8a7316c408fd91519f72c237805c4400b753e3942fda0b/zopfli-0.2.3.post1-cp312-cp312-win_amd64.whl", hash = "sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f", size = 99403 }, + { url = "https://files.pythonhosted.org/packages/2b/24/0e552e2efce9a20625b56e9609d1e33c2966be33fc008681121ec267daec/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051", size = 295485 }, + { url = "https://files.pythonhosted.org/packages/08/83/b2564369fb98797a617fe2796097b1d719a4937234375757ad2a3febc04b/zopfli-0.2.3.post1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f", size = 163000 }, + { url = "https://files.pythonhosted.org/packages/3c/55/81d419739c2aab35e19b58bce5498dcb58e6446e5eb69f2d3c748b1c9151/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a", size = 823699 }, + { url = "https://files.pythonhosted.org/packages/9e/91/89f07c8ea3c9bc64099b3461627b07a8384302235ee0f357eaa86f98f509/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6617fb10f9e4393b331941861d73afb119cd847e88e4974bdbe8068ceef3f73f", size = 826612 }, + { url = "https://files.pythonhosted.org/packages/41/31/46670fc0c7805d42bc89702440fa9b73491d68abbc39e28d687180755178/zopfli-0.2.3.post1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a53b18797cdef27e019db595d66c4b077325afe2fd62145953275f53d84ce40c", size = 851148 }, + { url = "https://files.pythonhosted.org/packages/22/00/71ad39277bbb88f9fd20fb786bd3ff2ea4025c53b31652a0da796fb546cd/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b78008a69300d929ca2efeffec951b64a312e9a811e265ea4a907ab546d79fa6", size = 1754215 }, + { url = "https://files.pythonhosted.org/packages/d0/4e/e542c508d20c3dfbef1b90fcf726f824f505e725747f777b0b7b7d1deb95/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa5f90d6298bda02a95bc8dc8c3c19004d5a4e44bda00b67ca7431d857b4b54", size = 1905988 }, + { url = "https://files.pythonhosted.org/packages/ba/a5/817ac1ecc888723e91dc172e8c6eeab9f48a1e52285803b965084e11bbd5/zopfli-0.2.3.post1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1", size = 1835907 }, + { url = "https://files.pythonhosted.org/packages/cd/35/2525f90c972d8aafc39784a8c00244eeee8e8221b26cbc576748ee9dc1cd/zopfli-0.2.3.post1-cp313-cp313-win32.whl", hash = "sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775", size = 82742 }, + { url = "https://files.pythonhosted.org/packages/2f/c6/49b27570923956d52d37363e8f5df3a31a61bd7719bb8718527a9df3ae5f/zopfli-0.2.3.post1-cp313-cp313-win_amd64.whl", hash = "sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de", size = 99408 }, +]