diff --git a/.forgejo/workflows/issue.yml b/.forgejo/workflows/issue.yml deleted file mode 100644 index 57cda79..0000000 --- a/.forgejo/workflows/issue.yml +++ /dev/null @@ -1,14 +0,0 @@ -on: - issues: - types: [opened, reopened, closed, labeled, edited] - -jobs: - test: - runs-on: self-hosted-nixos-x86_64 - steps: - - uses: https://data.forgejo.org/actions/checkout@v4 - - name: Check techtree-manager presence - run: | - test -e ~/.cache/fafo-techtree/techtree-manager - - name: Run techtree-manager - run: cd techtree-manager/ && nix-shell shell.nix --run ~/.cache/fafo-techtree/techtree-manager diff --git a/.forgejo/workflows/push.yml b/.forgejo/workflows/push.yml deleted file mode 100644 index 60584c4..0000000 --- a/.forgejo/workflows/push.yml +++ /dev/null @@ -1,17 +0,0 @@ -on: - push: - branches: - - 'main' - - 'poc' - -jobs: - build: - runs-on: self-hosted-nixos-x86_64 - steps: - - uses: https://code.forgejo.org/actions/checkout@v4 - - name: Build techtree manager tool - run: cd techtree-manager/ && nix-shell shell.nix --run "cargo build --release" - - name: Cache the techtree manager tool - run: | - mkdir -p ~/.cache/fafo-techtree - cp -v techtree-manager/target/release/techtree-manager ~/.cache/fafo-techtree/techtree-manager diff --git a/README.md b/README.md deleted file mode 100644 index af1bdae..0000000 --- a/README.md +++ /dev/null @@ -1,140 +0,0 @@ -FAFO Technology Tree -==================== -This repository tracks our "technology tree" — the steps towards our -overarching goals. - -A description of how this tech tree works can be found below. See -[Working with the Tech Tree](#working-with-the-tech-tree). - -## Full Technology Tree -Below, you can see the full technology tree. The issues in this repository -track the tree's elements. For a better overview, check each issue for a -filtered subtree that contains just the elements related to it. - -![FAFO Tech Tree](https://git.fa-fo.de/fafo/techtree/media/branch/render/techtree.svg) - -## Working with the Tech Tree -Fundamentally, the tech tree is built from the issues in this repository and -their interdependencies. For elements to be reached, create new issues and -select one of the `Type/###` labels to declare what kind it is: - -- Type/**Equipment** 🔬 — A piece of machinery that we need to acquire or get - running. Mainly things that can be bought instead of built. - -- Type/**Process** ⚗️ — A process we need to achieve. This means we need to - become able to perform this process reliably. - -- Type/**Development** 🔩 — A device, software, or other thing we need to develop. - This is _engineering_ work; making use of existing knowledge to build - something useful. - -- Type/**Research** 🧪 — A topic that we can or must research to unlock future - capabilities. In contrast to _Development_ elements, we cannot make use of - prior art here. So less engineering and more _science_. - -#### Dependencies -Once created, add dependencies between issues to model their relationships. -The CI of this repository will automatically update the tech tree accordingly. -In addition, each issue gets a partial representation of the subtree of -elements directly related to it. You can quickly see what is still missing to -achieve a particular element. And also what next steps will be unlocked once -an element has been achieved. - -There are no distinct types of dependencies. This was a choice in the name of -keeping the model simple. All dependencies are hard requirements. But also -check the next section on more thoughts about this... - -#### Modelling Approach -Finding the right balance between model complexity and expressiveness is -tricky. Following are some guidelines for adding elements to this tech tree. - -All elements should have a few fundamental properties, to keep the model consistent: - -- Elements shall have a **clear and unambiguous acceptance criterion**. If - necessary, this can be elaborated on in the issue body. "SEM Imaging" leaves - open what scale we can image reliably. It may be sensible to add multiple - elements to model progress in such a domain. - -- Elements shall be **actionable**, in the sense that someone can put in effort to - achieve them. Having a good acceptance criterion does most of the heavy - lifting here. - -- Elements shall be **necessary** for our bigger visions. Ultimate elements - (elements that nothing depends on) should get special consideration in this - regard. If you have visions of your own, it is of course fine to make an - ultimate element for them. - -- Elements shall have a scope/granularity size that is appropriate for tracking - progress. We will need to figure this out as we go. - -Generally, our tech tree is a living object. It should be updated as we figure -out more elements to be tracked and their dependencies. - -One topic of particular interest are "path choices". We can either use -technology A or technology B to achieve element C: - -```mermaid -flowchart BT - classDef eoi fill:#fff, stroke:#000, color:#000; - classDef dependant fill:#fff, stroke:#888, color:#888; - classDef dep_missing fill:#fcc, stroke:#800, color:#000; - classDef dep_assigned fill:#ffa, stroke:#a50, color:#000; - classDef dep_completed fill:#afa, stroke:#080, color:#000; - 0:::dep_missing - 0["#1 | MISSING
Process
Technology A"] - 1:::dep_completed - 1["#2 | COMPLETED
Process
Technology B"] - 2:::eoi - 2["#3 | MISSING
Process
Element C"] - 2 --> 0 - 2 --> 1 -``` - -Dependencies cannot express such choices. Instead, please follow this approach: - -- Initially, all potential path choice dependencies are added. The issue body - shall document the choice options and implications. - -- When we get closer to the element of interest, we make the choice of what - path to pursue. At this time, the other dependencies are dropped. The - tech-tree now only documents the path choice we have made. - -Another situation we will encounter is the need to use generic equipment for -specific purposes. If the specific purpose is non-trivial, it shall be -modelled as an intermediate _Process_ element in-between: - -```mermaid -flowchart BT - classDef eoi fill:#fff, stroke:#000, color:#000; - classDef dependant fill:#fff, stroke:#888, color:#888; - classDef dep_missing fill:#fcc, stroke:#800, color:#000; - classDef dep_assigned fill:#ffa, stroke:#a50, color:#000; - classDef dep_completed fill:#afa, stroke:#080, color:#000; - 0:::dep_missing - 0["#2 | MISSING
Process
Processing X using machine A"] - 1:::dep_completed - 1["#1 | COMPLETED
Equipment
Generic Machine A"] - 2:::eoi - 2["#3 | MISSING
Process
Element C"] - 2 --> 0 - 0 --> 1 -``` - - - -#### Element Status -The status of each element is determined as follows: - -- **MISSING** when the element has not yet been achieved. -- **ASSIGNED** when the issue has been assigned to someone. This means we are making progress! -- **COMPLETED** when the issue is labelled `Completed`. Achievement unlocked! - -#### Important notes -There are a few gotchas that you should be aware of: - -- The CI will not automatically update when changing dependencies, - unfortunately. You can force a trigger by editing the issue body or quickly - adding and then removing the `Stale` label. - -- Issues that should no longer be a part of the techtree should either be - deleted (looses all tracking) or they can be made inert by closing them. diff --git a/techtree-manager/.gitignore b/techtree-manager/.gitignore deleted file mode 100644 index 00df608..0000000 --- a/techtree-manager/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target/ -/render-git/ diff --git a/techtree-manager/Cargo.lock b/techtree-manager/Cargo.lock deleted file mode 100644 index 2cfb715..0000000 --- a/techtree-manager/Cargo.lock +++ /dev/null @@ -1,1988 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cc" -version = "1.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "forgejo-api" -version = "0.3.2" -source = "git+https://git.fa-fo.de/rahix/forgejo-api.git?rev=a3f6452cfe774898a89ac66be393e5205f5e12b7#a3f6452cfe774898a89ac66be393e5205f5e12b7" -dependencies = [ - "base64ct", - "bytes", - "reqwest", - "serde", - "serde_json", - "soft_assert", - "thiserror", - "time", - "tokio", - "url", - "zeroize", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jiff" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl" -version = "0.10.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a98c6720655620a521dcc722d0ad66cd8afd5d86e34a89ef691c50b7b24de06" -dependencies = [ - "fixedbitset", - "hashbrown", - "indexmap", - "serde", - "serde_derive", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "redox_syscall" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "reqwest" -version = "0.11.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" -dependencies = [ - "base64 0.21.7", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "mime_guess", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.1", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha256" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" -dependencies = [ - "async-trait", - "bytes", - "hex", - "sha2", - "tokio", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "soft_assert" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5097ec7ea7218135541ad96348f1441d0c616537dd4ed9c47205920c35d7d97" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "techtree-manager" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64 0.22.1", - "chrono", - "env_logger", - "forgejo-api", - "log", - "petgraph", - "serde", - "serde_json", - "sha256", - "time", - "tokio", - "url", -] - -[[package]] -name = "tempfile" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -dependencies = [ - "fastrand", - "getrandom", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/techtree-manager/Cargo.toml b/techtree-manager/Cargo.toml deleted file mode 100644 index bba5bc6..0000000 --- a/techtree-manager/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "techtree-manager" -version = "0.1.0" -edition = "2024" -authors = ["rahix "] -license = "MIT OR Apache-2.0" -publish = false - -[dependencies] -anyhow = "1.0.98" -base64 = "0.22.1" -chrono = "0.4.41" -env_logger = { version = "0.11.8", default-features = false, features = ["auto-color", "color", "humantime"] } -forgejo-api = { git = "https://git.fa-fo.de/rahix/forgejo-api.git", rev = "a3f6452cfe774898a89ac66be393e5205f5e12b7" } -log = "0.4.27" -petgraph = { version = "0.8.1", features = ["serde-1"] } -serde = { version = "1.0.219", features = ["derive"] } -serde_json = "1.0.140" -sha256 = "1.6.0" -time = "0.3.41" -tokio = { version = "1.45.0", features = ["full"] } -url = "2.5.4" diff --git a/techtree-manager/LICENSE-APACHE b/techtree-manager/LICENSE-APACHE deleted file mode 100644 index 261eeb9..0000000 --- a/techtree-manager/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/techtree-manager/LICENSE-MIT b/techtree-manager/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/techtree-manager/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/techtree-manager/shell.nix b/techtree-manager/shell.nix deleted file mode 100644 index c893b75..0000000 --- a/techtree-manager/shell.nix +++ /dev/null @@ -1,21 +0,0 @@ -# From 2025-05-21 -let pkgs = import (fetchTarball("https://github.com/NixOS/nixpkgs/archive/36ecfe6216f0aa7f2a1ffe5aafc2c0eae6c8cdcf.tar.gz")) {}; - -in pkgs.mkShell { - buildInputs = [ - # Rust - pkgs.cargo - pkgs.rustc - pkgs.rustfmt - - # Dependencies - pkgs.openssl - pkgs.graphviz - pkgs.git - ]; - - shellHook = '' - export OPENSSL_DIR="${pkgs.openssl.dev}" - export OPENSSL_LIB_DIR="${pkgs.openssl.out}/lib" - ''; -} diff --git a/techtree-manager/src/collect.rs b/techtree-manager/src/collect.rs deleted file mode 100644 index ef3eca1..0000000 --- a/techtree-manager/src/collect.rs +++ /dev/null @@ -1,156 +0,0 @@ -use anyhow::Context as _; - -/// Read all issues to generate the full techtree -pub async fn collect_tree(ctx: &crate::Context) -> anyhow::Result { - let mut issues = vec![]; - for page in 1.. { - let new = ctx - .forgejo - .issue_list_issues( - &ctx.owner, - &ctx.repo, - forgejo_api::structs::IssueListIssuesQuery { - // We also want the closed issues - state: Some(forgejo_api::structs::IssueListIssuesQueryState::All), - // We cannot turn off pagination entirely, but let's set the limit as high as - // Forgejo lets us. - limit: Some(10000), - page: Some(page), - // Only issues - r#type: Some(forgejo_api::structs::IssueListIssuesQueryType::Issues), - ..Default::default() - }, - ) - .await - .with_context(|| format!("Failed fetching page {page} of the issue list"))?; - - if new.len() == 0 { - break; - } - - issues.extend(new); - } - - let mut tree = crate::tree::Tree::new(); - let mut issue_numbers = Vec::new(); - - for issue in issues.iter() { - let element = match element_from_issue(issue) { - Ok(el) => el, - Err(e) => { - let maybe_number = issue - .number - .map(|n| n.to_string()) - .unwrap_or("".to_owned()); - log::warn!("Failed processing issue #{maybe_number}: {e:?}"); - continue; - } - }; - - issue_numbers.push(element.issue_number); - tree.add_element(element); - } - - for issue in issue_numbers.into_iter() { - let dependencies = ctx - .forgejo - .issue_list_issue_dependencies( - &ctx.owner, - &ctx.repo, - // Why the hell is the issue number a string here? - &issue.to_string(), - forgejo_api::structs::IssueListIssueDependenciesQuery { - limit: Some(10000), - ..Default::default() - }, - ) - .await - .with_context(|| format!("Failed to fetch issue dependencies for #{issue}",))?; - - for dep in dependencies { - // Check that the dependency is actually an issue in the techtree and not external - let dep_repo = dep - .repository - .context("Dependency issue without repository info")?; - if dep_repo.owner.as_ref() != Some(&ctx.owner) - || dep_repo.name.as_ref() != Some(&ctx.repo) - { - log::warn!( - "Issue #{issue} depends on external {}#{}, ignoring.", - dep_repo.full_name.as_deref().unwrap_or("unknown?"), - dep.number.unwrap_or(9999) - ); - continue; - } - - let dep_number = dep.number.context("Missing issue number in dependency")?; - if !tree.find_element_by_issue_number(dep_number).is_some() { - log::warn!("Found dependency from #{issue} on non-tracked issue #{dep_number}!"); - } else { - tree.add_dependency_by_issue_number(issue, dep_number); - } - } - } - - Ok(tree) -} - -fn element_from_issue(issue: &forgejo_api::structs::Issue) -> anyhow::Result { - let issue_number = issue.number.context("Missing issue number")?; - let description = issue - .title - .as_deref() - .context("Issue is missing a title")? - .to_owned(); - - let labels = issue - .labels - .as_ref() - .context("Issue does not have any labels")?; - - let ty_labels: Vec<_> = labels - .iter() - .filter_map(|l| l.name.as_deref()) - .filter_map(|l| l.strip_prefix("Type/")) - .collect(); - - let ty = match &ty_labels[..] { - [ty] => ty.to_string(), - [] => { - anyhow::bail!("Issue #{issue_number} has no type label!"); - } - [..] => { - anyhow::bail!("Issue #{issue_number} has more than one type label!"); - } - }; - - let has_completed_label = labels - .iter() - .any(|l| l.name.as_deref() == Some("Completed")); - - let status = match issue.state.context("Missing issue state")? { - forgejo_api::structs::StateType::Open => { - if has_completed_label { - crate::tree::ElementStatus::Completed - } else if issue.assignee.is_some() - || issue - .assignees - .as_ref() - .map(|v| v.len() > 0) - .unwrap_or(false) - { - crate::tree::ElementStatus::Assigned - } else { - crate::tree::ElementStatus::Missing - } - } - forgejo_api::structs::StateType::Closed => anyhow::bail!("Ignoring closed issue!"), - }; - - Ok(crate::tree::Element { - issue_number, - description, - ty, - status, - }) -} diff --git a/techtree-manager/src/event_meta.rs b/techtree-manager/src/event_meta.rs deleted file mode 100644 index bcc0d83..0000000 --- a/techtree-manager/src/event_meta.rs +++ /dev/null @@ -1,57 +0,0 @@ -use anyhow::Context as _; - -#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct IssueEventMeta { - pub action: IssueAction, - pub issue: IssueMeta, -} - -#[derive(serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)] -#[serde(rename_all = "lowercase")] -pub enum IssueAction { - Opened, - Reopened, - Closed, - Assigned, - Unassigned, - Edited, - #[serde(rename = "label_updated")] - LabelUpdated, - Labeled, - #[serde(rename = "label_cleared")] - LabelCleared, - Unlabeled, -} - -#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct IssueMeta { - pub number: u64, - pub repository: RepoMeta, -} - -#[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct RepoMeta { - pub name: String, - pub owner: String, -} - -pub fn get_issue_event_meta_from_env() -> anyhow::Result { - let path = std::env::var_os("GITHUB_EVENT_PATH") - .context("Could not get event description file path (GITHUB_EVENT_PATH)")?; - let f = std::fs::File::open(path).context("Could not open GITHUB_EVENT_PATH file")?; - let meta: IssueEventMeta = serde_json::de::from_reader(f).context("Failed to parse")?; - Ok(meta) -} - -pub fn fake() -> IssueEventMeta { - IssueEventMeta { - action: IssueAction::Edited, - issue: IssueMeta { - number: 1337, - repository: RepoMeta { - name: "techtree".to_owned(), - owner: "fafo".to_owned(), - }, - }, - } -} diff --git a/techtree-manager/src/issue.rs b/techtree-manager/src/issue.rs deleted file mode 100644 index 97cf9d9..0000000 --- a/techtree-manager/src/issue.rs +++ /dev/null @@ -1,191 +0,0 @@ -use anyhow::Context as _; - -pub type CommentId = u64; - -pub struct BotCommentInfo { - pub body: String, - pub id: CommentId, -} - -pub async fn make_bot_comment( - ctx: &crate::Context, - issue_number: u64, -) -> anyhow::Result { - let initial_message = - "_Please be patient, this issue is currently being integrated into the techtree..._"; - - let res = ctx - .forgejo - .issue_create_comment( - &ctx.owner, - &ctx.repo, - issue_number, - forgejo_api::structs::CreateIssueCommentOption { - body: initial_message.to_owned(), - updated_at: None, - }, - ) - .await?; - - Ok(BotCommentInfo { - id: res.id.context("Missing id for the bot comment")?, - body: initial_message.to_owned(), - }) -} - -pub async fn find_bot_comment( - ctx: &crate::Context, - issue_number: u64, -) -> anyhow::Result> { - let mut comments = ctx - .forgejo - .issue_get_comments( - &ctx.owner, - &ctx.repo, - issue_number, - forgejo_api::structs::IssueGetCommentsQuery { - ..Default::default() - }, - ) - .await - .context("Failed fetching comments for issue")?; - - comments.sort_by_key(|comment| comment.created_at); - - let maybe_bot_comment = comments - .iter() - .rev() - .find(|comment| comment.user.as_ref().and_then(|u| u.id) == Some(-2)); - - Ok(maybe_bot_comment - .map(|c| -> anyhow::Result<_> { - Ok(BotCommentInfo { - body: c.body.clone().unwrap_or("".to_owned()), - id: c.id.context("Missing id for the bot comment")?, - }) - }) - .transpose()?) -} - -/// Find existing bot comment or create a new one. -/// -/// Returns a tuple of the comment information and a boolean indicating whether the comment was -/// newly created. -pub async fn find_or_make_bot_comment( - ctx: &crate::Context, - issue_number: u64, -) -> anyhow::Result<(BotCommentInfo, bool)> { - if let Some(comment) = find_bot_comment(ctx, issue_number) - .await - .context("Failed to search for bot comment in issue")? - { - Ok((comment, false)) - } else { - make_bot_comment(ctx, issue_number) - .await - .context("Failed to make new bot comment in issue") - .map(|c| (c, true)) - } -} - -pub async fn update_bot_comment( - ctx: &crate::Context, - id: CommentId, - new_body: String, -) -> anyhow::Result<()> { - ctx.forgejo - .issue_edit_comment( - &ctx.owner, - &ctx.repo, - id, - forgejo_api::structs::EditIssueCommentOption { - body: new_body, - updated_at: None, - }, - ) - .await - .context("Failed to update comment body")?; - - Ok(()) -} - -pub async fn update_bot_comment_from_subtree( - ctx: &crate::Context, - id: CommentId, - subtree: &crate::tree::Subtree<'_>, - hash: &str, -) -> anyhow::Result<()> { - let mut mermaid = subtree.to_mermaid(&ctx.repo_url.to_string(), false); - - // When the mermaid graph gets too big, regenerate a simplified version. - if mermaid.len() > 4990 { - log::info!("Mermaid graph is too big, generating simplified version..."); - mermaid = subtree.to_mermaid(&ctx.repo_url.to_string(), true); - } - - let full_text = if mermaid.len() > 4990 { - format!( - r##"## Partial Techtree -_Sorry, the partial techtree is still too big to be displayed for this element..._ - -Digest: {hash}; Last Updated: {timestamp}"##, - timestamp = ctx.timestamp, - ) - } else { - format!( - r##"## Partial Techtree -```mermaid -{mermaid} -``` - -Digest: {hash}; Last Updated: {timestamp}"##, - timestamp = ctx.timestamp, - ) - }; - - update_bot_comment(&ctx, id, full_text).await?; - - Ok(()) -} - -pub async fn remove_stale_label(ctx: &crate::Context, issue_number: u64) -> anyhow::Result<()> { - let labels = ctx - .forgejo - .issue_get_labels(&ctx.owner, &ctx.repo, issue_number) - .await - .context("Failed fetching issue labels")?; - - let stale_label_id = labels - .iter() - .filter(|l| l.name.as_deref() == Some("Stale")) - .next() - .map(|l| l.id.ok_or(anyhow::anyhow!("`Stale` label has no ID"))) - .transpose()?; - - if let Some(stale_label_id) = stale_label_id { - log::info!("Removing `Stale` label from issue #{issue_number}..."); - - let res = ctx - .forgejo - .issue_remove_label( - &ctx.owner, - &ctx.repo, - issue_number, - stale_label_id, - forgejo_api::structs::DeleteLabelsOption { - updated_at: Some(time::OffsetDateTime::now_utc()), - }, - ) - .await; - - if let Err(e) = res { - // At the moment, the token for Forgejo Actions cannot remove issue labels. - // See https://codeberg.org/forgejo/forgejo/issues/2415 - log::warn!( - "Failed to remove `Stale` label for #{issue_number}. This is a known Forgejo limitation at the moment... ({e})" - ); - } - } - - Ok(()) -} diff --git a/techtree-manager/src/main.rs b/techtree-manager/src/main.rs deleted file mode 100644 index eda6053..0000000 --- a/techtree-manager/src/main.rs +++ /dev/null @@ -1,181 +0,0 @@ -#![allow(dead_code)] - -use anyhow::Context as _; -use forgejo_api::Forgejo; - -mod collect; -mod event_meta; -mod issue; -mod render; -mod tree; -mod wiki; - -pub struct Context { - /// API Accessor object - pub forgejo: forgejo_api::Forgejo, - /// Repository Owner - pub owner: String, - /// Repository Name - pub repo: String, - /// URL of the repository page - pub repo_url: url::Url, - /// URL of the repository with authentication information attached - pub repo_auth_url: Option, - /// Human readable timestamp of this manager run - pub timestamp: String, -} - -async fn run() -> anyhow::Result<()> { - let meta = if std::env::var("TECHTREE_FAKE").ok().is_some() { - log::warn!("Fake tree!"); - event_meta::fake() - } else { - event_meta::get_issue_event_meta_from_env() - .context("Maybe you want to run with TECHTREE_FAKE=1?") - .context("Failed reading issue event data")? - }; - - log::info!( - "Running due to event \"{:?}\" on issue #{} ...", - meta.action, - meta.issue.number - ); - - let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S").to_string(); - log::info!("Timestamp of this run is {timestamp}"); - - let token = std::env::var("GITHUB_TOKEN").ok(); - if token.is_none() { - log::warn!("No GITHUB_TOKEN, only performing read-only operations!"); - } - - let server_url = url::Url::parse(&std::env::var("GITHUB_SERVER_URL").unwrap_or_else(|_e| { - log::warn!("Using FAFO URL as a default GITHUB_SERVER_URL!"); - "https://git.fa-fo.de".to_string() - })) - .context("Failed parsing GITHUB_SERVER_URL as a url")?; - - let repo_url = server_url - .join(&format!( - "{}/{}", - meta.issue.repository.owner, meta.issue.repository.name - )) - .with_context(|| { - format!("failed building repository URL from GITHUB_SERVER_URL: {server_url}") - })?; - - let repo_auth_url = token - .as_ref() - .map(|token| -> Result<_, ()> { - let mut repo_auth_url = repo_url.clone(); - repo_auth_url.set_username("forgejo-actions")?; - repo_auth_url.set_password(Some(&token))?; - Ok(repo_auth_url) - }) - .transpose() - .map_err(|_e| anyhow::anyhow!("Repo URL does not have correct format")) - .context("Failed adding auth info to repo URL")?; - - let auth = if let Some(token) = token.as_ref() { - forgejo_api::Auth::Token(token) - } else { - forgejo_api::Auth::None - }; - let forgejo = - Forgejo::new(auth, server_url).context("Could not create Forgejo API access object")?; - - let ctx = Context { - forgejo, - owner: meta.issue.repository.owner.clone(), - repo: meta.issue.repository.name.clone(), - repo_url, - repo_auth_url, - timestamp, - }; - - if meta.action == event_meta::IssueAction::Opened { - log::debug!("Running for a newly opened issue. Taking care of the comment first..."); - match issue::find_or_make_bot_comment(&ctx, meta.issue.number).await { - Ok((_comment, is_new)) => { - if is_new { - log::info!( - "Waiting for a minute, as the issue is brand new. We will likely catch some more updates this way!" - ); - tokio::time::sleep(std::time::Duration::from_secs(60)).await; - } - } - Err(err) => { - log::warn!( - "Error while commenting on new issue #{}, continuing anyway... Error: {err:?}", - meta.issue.number - ); - } - } - } - - log::info!("Collecting tree from issue metadata..."); - let tree = collect::collect_tree(&ctx) - .await - .context("Failed to collect the techtree from issue metadata")?; - - log::info!("Rendering and publishing techtree to git repository..."); - let rendered_tree = render::render(&ctx, &tree) - .await - .context("Failed to render the techtree")?; - - if token.is_some() { - render::publish(&ctx, &rendered_tree) - .await - .context("Failed to publish rendered tree to git")?; - } else { - log::warn!("Skipped publishing the rendered tree."); - } - - // Wiki is disabled because the tree is too big for mermaid to handle - if false { - log::info!("Updating the wiki overview..."); - wiki::update_wiki_from_tree(&ctx, &tree) - .await - .context("Failed to update the techtree wiki page")?; - } - - if token.is_none() { - log::warn!("Not running issue updates without token."); - return Ok(()); - } - - 'issues: for issue in tree.iter_issues() { - let subtree = tree.subtree_for_issue(issue).expect("issue from tree not found in tree"); - let hash = subtree.stable_hash(); - - let (bot_comment, _is_new) = issue::find_or_make_bot_comment(&ctx, issue) - .await - .with_context(|| format!("Failed to find or make bot comment in issue #{issue}"))?; - - if bot_comment.body.contains(&hash) { - log::debug!("Issue #{issue} is up to date, not editing comment."); - issue::remove_stale_label(&ctx, issue) - .await - .with_context(|| format!("Failed to remove `Stale` label from issue #{issue}"))?; - - continue 'issues; - } - - log::info!("Updating bot comment in issue #{issue} ..."); - issue::update_bot_comment_from_subtree(&ctx, bot_comment.id, &subtree, &hash) - .await - .with_context(|| format!("Failed to update bot comment in issue #{issue}"))?; - - issue::remove_stale_label(&ctx, issue) - .await - .with_context(|| format!("Failed to remove `Stale` label from issue #{issue}"))?; - } - - Ok(()) -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); - run().await -} diff --git a/techtree-manager/src/render.rs b/techtree-manager/src/render.rs deleted file mode 100644 index f18bebb..0000000 --- a/techtree-manager/src/render.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::process::Command; - -use anyhow::Context as _; - -trait SuccessExt { - fn success(&mut self) -> anyhow::Result<()>; -} - -impl SuccessExt for Command { - fn success(&mut self) -> anyhow::Result<()> { - if !self.status()?.success() { - anyhow::bail!("Command returned unsuccessfully"); - } - Ok(()) - } -} - -pub struct RenderedTree { - pub repo_dir: std::path::PathBuf, - pub dot_file_name: std::ffi::OsString, - pub svg_file_name: std::ffi::OsString, -} - -impl RenderedTree { - pub fn dot_file(&self) -> std::path::PathBuf { - self.repo_dir.join(&self.dot_file_name) - } - - pub fn svg_file(&self) -> std::path::PathBuf { - self.repo_dir.join(&self.svg_file_name) - } -} - -pub async fn render( - _ctx: &crate::Context, - tree: &crate::tree::Tree, -) -> anyhow::Result { - let repo_dir = std::path::PathBuf::from("render-git"); - - let info = RenderedTree { - repo_dir, - dot_file_name: "techtree.dot".into(), - svg_file_name: "techtree.svg".into(), - }; - - if info.repo_dir.is_dir() { - log::info!("Found old {:?} repository, removing...", info.repo_dir); - std::fs::remove_dir_all(&info.repo_dir) - .context("Failed to remove stale render repository")?; - } - - std::fs::create_dir(&info.repo_dir).context("Failed creating directory for rendered graph")?; - - let dot_source = tree.to_dot(); - std::fs::write(&info.dot_file(), dot_source.as_bytes()) - .context("Failed to write `dot` source file")?; - - Command::new("dot") - .args(["-T", "svg"]) - .arg("-o") - .arg(&info.svg_file()) - .arg(&info.dot_file()) - .success() - .context("Failed to generate svg graph from dot source")?; - - Ok(info) -} - -pub async fn publish(ctx: &crate::Context, rendered: &RenderedTree) -> anyhow::Result<()> { - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .arg("init") - .arg("--initial-branch=render") - .arg("--quiet") - .success() - .context("Failed to initialize render repository")?; - - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .args(["config", "user.email", "git@fa-fo.de"]) - .success() - .context("Failed to configure identity for render repo")?; - - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .args(["config", "user.name", "Forgejo Actions"]) - .success() - .context("Failed to configure identity for render repo")?; - - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .arg("add") - .arg(&rendered.dot_file_name) - .arg(&rendered.svg_file_name) - .success() - .context("Failed to add generated graph files to git index")?; - - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .arg("commit") - .arg("--quiet") - .args(["-m", &format!("Updated techtree at {}", ctx.timestamp)]) - .success() - .context("Failed to add generated graph files to git index")?; - - Command::new("git") - .arg("-C") - .arg(&rendered.repo_dir) - .arg("push") - .arg("--force") - .arg("--quiet") - .arg( - ctx.repo_auth_url - .as_ref() - .expect("cannot publish without authentication token") - .to_string(), - ) - .arg("HEAD:refs/heads/render") - .status() - .context("Failed to push rendered graph to forgejo repository")?; - - Ok(()) -} diff --git a/techtree-manager/src/tree.rs b/techtree-manager/src/tree.rs deleted file mode 100644 index 3ec271f..0000000 --- a/techtree-manager/src/tree.rs +++ /dev/null @@ -1,433 +0,0 @@ -use std::collections::BTreeMap; - -use petgraph::visit::EdgeRef as _; - -const HASH_EPOCH: u32 = 0x00000001; - -/// Element in the techtree -#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize)] -pub struct Element { - /// Issue associated with this element - pub issue_number: u64, - /// Description of this element - pub description: String, - /// Type of this element - pub ty: String, - /// Completion status of this element. - pub status: ElementStatus, -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum ElementRole { - Root, - Ultimate, - Intermediate, - Disjoint, -} - -impl Element { - fn to_dot_node_attributes( - &self, - role: Option, - subtree_role: Option, - ) -> String { - let Element { - issue_number, - description, - ty, - status, - } = self; - - let mut attributes = Vec::new(); - - let description = description - .replace("<", "<") - .replace(">", ">") - .replace("&", "&") - .replace("'", "'") - .replace("\"", """); - - attributes.push(format!( - r##"label = <{{{{#{issue_number} | {status}}}|{ty}|{description}}}>"## - )); - attributes.push(r#"shape = "record""#.to_owned()); - - let (color, background) = match (subtree_role, status) { - (Some(SubtreeElementRole::ElementOfInterest), _) => ("black", "white"), - (Some(SubtreeElementRole::Dependant), _) => ("gray", "gray"), - (_, ElementStatus::Missing) => ( - "#800", - // Highlight root elements - if role == Some(ElementRole::Root) { - "#ffddc1" - } else { - "#fcc" - }, - ), - (_, ElementStatus::Assigned) => ("#a50", "#ffa"), - (_, ElementStatus::Completed) => ("#080", "#afa"), - }; - attributes.push(format!(r#"color = "{color}""#)); - attributes.push(format!(r#"fontcolor = "{color}""#)); - attributes.push(format!(r#"fillcolor = "{background}""#)); - attributes.push(format!(r#"style = "filled""#)); - - attributes.join(", ") - } - - fn to_mermaid_node( - &self, - index: ElementIndex, - role: Option, - repo_url: &str, - simple: bool, - ) -> String { - let Element { - issue_number, - description, - ty, - status, - } = self; - - let label = if simple { - format!(r##"#{issue_number} | {status}
{ty}
{description}"##) - } else { - format!( - r##"#{issue_number} | {status}
{ty}
{description}"## - ) - }; - - let class = match (role, status) { - (Some(SubtreeElementRole::ElementOfInterest), _) => "eoi", - (Some(SubtreeElementRole::Dependant), _) => "dependant", - (_, ElementStatus::Missing) => "dep_missing", - (_, ElementStatus::Assigned) => "dep_assigned", - (_, ElementStatus::Completed) => "dep_completed", - }; - - format!( - " {index}:::{class}\n {index}[\"{label}\"]", - index = index.index(), - ) - } -} - -fn mermaid_classes() -> String { - r##" - classDef eoi fill:#fff, stroke:#000, color:#000; - classDef dependant fill:#fff, stroke:#888, color:#888; - classDef dep_missing fill:#fcc, stroke:#800, color:#000; - classDef dep_assigned fill:#ffa, stroke:#a50, color:#000; - classDef dep_completed fill:#afa, stroke:#080, color:#000; -"## - .to_owned() -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize)] -pub enum ElementStatus { - Missing, - Assigned, - Completed, -} - -impl std::fmt::Display for ElementStatus { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - ElementStatus::Missing => "MISSING", - ElementStatus::Assigned => "ASSIGNED", - ElementStatus::Completed => "COMPLETED", - }) - } -} - -pub type ElementIndex = petgraph::graph::NodeIndex; - -#[derive(serde::Serialize)] -pub struct Tree { - graph: petgraph::Graph, - #[serde(skip)] - issue_map: BTreeMap, -} - -impl Tree { - pub fn new() -> Self { - Self { - graph: petgraph::Graph::new(), - issue_map: BTreeMap::new(), - } - } - - pub fn add_element(&mut self, element: Element) { - let issue_number = element.issue_number; - assert!(!self.issue_map.contains_key(&issue_number)); - let idx = self.graph.add_node(element); - self.issue_map.insert(issue_number, idx); - } - - pub fn add_dependency_by_issue_number(&mut self, dependant: u64, dependency: u64) { - let a = self - .find_element_by_issue_number(dependant) - .expect("dependant element does not exist"); - let b = self - .find_element_by_issue_number(dependency) - .expect("dependency element does not exist"); - self.graph.add_edge(a, b, ()); - } - - pub fn find_element_by_issue_number(&self, issue_number: u64) -> Option { - self.issue_map.get(&issue_number).copied() - } - - pub fn subtree_for_issue<'a>(&'a self, issue_number: u64) -> Option> { - Some(Subtree::new_for_element( - self, - self.find_element_by_issue_number(issue_number)?, - )) - } - - pub fn iter_issues<'a>(&'a self) -> impl Iterator + 'a { - self.issue_map.keys().copied() - } - - pub fn subtree_for_element<'a>(&'a self, element: ElementIndex) -> Subtree<'a> { - Subtree::new_for_element(self, element) - } - - pub fn iter_ultimate_elements<'a>(&'a self) -> impl Iterator + 'a { - self.graph.node_indices().filter(|index| { - // If there are no incoming edges, then this is an ultimate element! - self.graph - .neighbors_directed(*index, petgraph::Direction::Incoming) - .next() - .is_none() - }) - } - - pub fn get_element_role(&self, element: ElementIndex) -> ElementRole { - let has_dependencies = self - .graph - .neighbors_directed(element, petgraph::Direction::Outgoing) - .next() - .is_some(); - let has_dependants = self - .graph - .neighbors_directed(element, petgraph::Direction::Incoming) - .next() - .is_some(); - - match (has_dependencies, has_dependants) { - (false, true) => ElementRole::Root, - (true, false) => ElementRole::Ultimate, - (true, true) => ElementRole::Intermediate, - (false, false) => ElementRole::Disjoint, - } - } - - pub fn to_dot(&self) -> String { - let to_node_attributes = |_g, (id, element): (ElementIndex, &Element)| { - element.to_dot_node_attributes(Some(self.get_element_role(id)), None) - }; - let dot = petgraph::dot::Dot::with_attr_getters( - &self.graph, - &[ - petgraph::dot::Config::EdgeNoLabel, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::RankDir(petgraph::dot::RankDir::BT), - petgraph::dot::Config::GraphContentOnly, - ], - &|_g, _edge_id| "".to_string(), - &to_node_attributes, - ); - - let ultimate_elements: Vec<_> = self - .iter_ultimate_elements() - .map(|idx| idx.index().to_string()) - .collect(); - let ultimate_element_list = ultimate_elements.join("; "); - - format!( - r#"digraph {{ - ranksep=1.2 - {{ rank=same; {ultimate_element_list}; }} -{:?} -}} -"#, - dot - ) - } - - pub fn to_mermaid(&self, repo_url: &str, simple: bool) -> String { - let mut mermaid = String::new(); - mermaid.push_str("flowchart BT\n"); - mermaid.push_str(&mermaid_classes()); - - for index in self.graph.node_indices() { - mermaid.push_str(&self.graph[index].to_mermaid_node(index, None, repo_url, simple)); - mermaid.push_str("\n"); - } - - for edge in self.graph.edge_references() { - mermaid.push_str(&format!( - " {} --> {}\n", - edge.source().index(), - edge.target().index() - )); - } - - mermaid - } -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize)] -pub struct SubtreeElement<'a> { - element: &'a Element, - role: SubtreeElementRole, -} - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, serde::Serialize)] -pub enum SubtreeElementRole { - ElementOfInterest, - Dependency, - Dependant, -} - -pub struct Subtree<'a> { - original: &'a Tree, - graph: petgraph::Graph, ()>, - index_map: BTreeMap, -} - -impl<'a> Subtree<'a> { - pub fn new_for_element(tree: &'a Tree, element: ElementIndex) -> Subtree<'a> { - let mut this = Self { - original: tree, - graph: petgraph::Graph::new(), - index_map: BTreeMap::new(), - }; - let graph = &this.original.graph; - - this.add_node_if_missing(element, SubtreeElementRole::ElementOfInterest); - - let mut dfs = petgraph::visit::Dfs::new(&graph, element); - while let Some(idx) = dfs.next(&graph) { - this.add_node_if_missing(idx, SubtreeElementRole::Dependency); - } - - for idx in this.index_map.keys().copied() { - for neighbor in graph.neighbors_directed(idx, petgraph::Direction::Outgoing) { - if !this.index_map.contains_key(&neighbor) { - log::warn!( - "Probably missed a dependency from #{from} to #{to} while generating subtree for #{el}", - el = graph[element].issue_number, - from = graph[idx].issue_number, - to = graph[neighbor].issue_number - ); - continue; - } - - this.graph - .add_edge(this.index_map[&idx], this.index_map[&neighbor], ()); - } - } - - for neighbor in graph.neighbors_directed(element, petgraph::Direction::Incoming) { - if this.index_map.contains_key(&neighbor) { - log::warn!( - "Already found #{from} in dependencies of #{to}, but it should have been the other way around?!", - from = graph[neighbor].issue_number, - to = graph[element].issue_number - ); - } else { - this.add_node_if_missing(neighbor, SubtreeElementRole::Dependant); - } - - this.graph - .add_edge(this.index_map[&neighbor], this.index_map[&element], ()); - } - - this - } - - fn add_node_if_missing(&mut self, index: ElementIndex, role: SubtreeElementRole) -> bool { - if self.index_map.contains_key(&index) { - debug_assert!(self.graph.node_weight(self.index_map[&index]).is_some()); - return false; - } - - let subtree_element = SubtreeElement { - element: &self.original.graph[index], - role, - }; - - let new_idx = self.graph.add_node(subtree_element); - self.index_map.insert(index, new_idx); - - return true; - } - - pub fn to_dot(&self) -> String { - let dot = petgraph::dot::Dot::with_attr_getters( - &self.graph, - &[ - petgraph::dot::Config::EdgeNoLabel, - petgraph::dot::Config::NodeNoLabel, - petgraph::dot::Config::RankDir(petgraph::dot::RankDir::BT), - ], - &|_g, _edge_id| "".to_string(), - &|_g, (_, element)| { - element - .element - .to_dot_node_attributes(None, Some(element.role)) - }, - ); - - format!("{:?}", dot) - } - - pub fn to_mermaid(&self, repo_url: &str, simple: bool) -> String { - let mut mermaid = String::new(); - mermaid.push_str("flowchart BT\n"); - mermaid.push_str(&mermaid_classes()); - - for index in self.graph.node_indices() { - let node = &self.graph[index]; - mermaid.push_str(&node.element.to_mermaid_node( - index, - Some(node.role), - repo_url, - simple, - )); - mermaid.push_str("\n"); - } - - for edge in self.graph.edge_references() { - mermaid.push_str(&format!( - " {} --> {}\n", - edge.source().index(), - edge.target().index() - )); - } - - mermaid - } - - pub fn stable_hash(&self) -> String { - let mut nodes: Vec<_> = self.graph.node_weights().collect(); - nodes.sort_by_key(|n| n.element.issue_number); - let mut edges: Vec<_> = self - .graph - .edge_references() - .map(|edge| { - ( - self.graph[edge.source()].element.issue_number, - self.graph[edge.target()].element.issue_number, - ) - }) - .collect(); - edges.sort(); - - let json_data = serde_json::ser::to_string(&(nodes, edges, HASH_EPOCH)) - .expect("serialization for a stable hash failed"); - sha256::digest(json_data) - } -} diff --git a/techtree-manager/src/wiki.rs b/techtree-manager/src/wiki.rs deleted file mode 100644 index e61f931..0000000 --- a/techtree-manager/src/wiki.rs +++ /dev/null @@ -1,40 +0,0 @@ -use anyhow::Context as _; -use base64::prelude::*; - -pub async fn update_wiki_from_tree( - ctx: &crate::Context, - tree: &crate::tree::Tree, -) -> anyhow::Result<()> { - let mermaid = tree.to_mermaid(&ctx.repo_url.to_string(), false); - let wiki_text = format!( - r##"This page is automatically updated to show the latest and greatest FAFO techtree: - -```mermaid -{mermaid} -``` -"## - ); - update_wiki_overview(&ctx, wiki_text) - .await - .context("Failed to update the techtree wiki page")?; - Ok(()) -} - -pub async fn update_wiki_overview(ctx: &crate::Context, new_body: String) -> anyhow::Result<()> { - // TODO: Figure out why we get a 404 when the edit was successfull... - let _ = ctx - .forgejo - .repo_edit_wiki_page( - &ctx.owner, - &ctx.repo, - "Home", - forgejo_api::structs::CreateWikiPageOptions { - content_base64: Some(BASE64_STANDARD.encode(new_body.as_bytes())), - message: Some(format!("Updated to latest model at {}", ctx.timestamp)), - title: Some("Home".to_owned()), - }, - ) - .await - .context("Failed editing the wiki page"); - Ok(()) -} diff --git a/techtree.dot b/techtree.dot new file mode 100644 index 0000000..18151c7 --- /dev/null +++ b/techtree.dot @@ -0,0 +1,278 @@ +digraph { + ranksep=1.2 + { rank=same; 0; 1; 2; 3; 4; 9; 25; 50; } + rankdir="BT" + 0 [ label = <{{#115 | MISSING}|Process|Semiconductor Manufacturing}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 1 [ label = <{{#114 | MISSING}|Process|Semiconductor & Electronics Analysis}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 2 [ label = <{{#113 | MISSING}|Process|Science Communication}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 3 [ label = <{{#112 | MISSING}|Process|Nanoscale Imaging}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 4 [ label = <{{#111 | MISSING}|Process|LIN supply}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 5 [ label = <{{#110 | ASSIGNED}|Equipment|Local NAS/server}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 6 [ label = <{{#109 | MISSING}|Equipment|Environmental Chamber}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 7 [ label = <{{#108 | MISSING}|Development|Piezo Driver}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 8 [ label = <{{#107 | MISSING}|Process|EMI Precompliance Testing}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 9 [ label = <{{#106 | MISSING}|Process|Electronics Distribution}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 10 [ label = <{{#105 | ASSIGNED}|Process|Create a Backlit LCD Device}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 11 [ label = <{{#104 | ASSIGNED}|Process|Electroluminescence Foil}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 12 [ label = <{{#103 | MISSING}|Process|Create a Matrix LCD Device}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 13 [ label = <{{#102 | ASSIGNED}|Research|Acquire Liquid Crystal Fluid}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 14 [ label = <{{#101 | MISSING}|Process|Chemical Vapor Deposition}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 15 [ label = <{{#100 | MISSING}|Process|Etch fractals on wafers}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 16 [ label = <{{#99 | ASSIGNED}|Process|Create an LCD Device}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 17 [ label = <{{#98 | ASSIGNED}|Development|Gridfinity-compatible JEDEC IC holders}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 18 [ label = <{{#97 | COMPLETED}|Equipment|PCB Rework Microscope}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 19 [ label = <{{#96 | COMPLETED}|Equipment|Soldering Station}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 20 [ label = <{{#95 | MISSING}|Equipment|Thermal Camera}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 21 [ label = <{{#94 | ASSIGNED}|Process|PCB Reverse Engineering}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 22 [ label = <{{#93 | COMPLETED}|Equipment|HEPA Fume Extractor}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 23 [ label = <{{#92 | COMPLETED}|Equipment|Miscellaneous Tools for BGA Rework}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 24 [ label = <{{#91 | COMPLETED}|Equipment|Hot Air Rework Station}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 25 [ label = <{{#90 | ASSIGNED}|Process|PCB Repair & Rework}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 26 [ label = <{{#89 | ASSIGNED}|Process|PCB Delayering}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 27 [ label = <{{#88 | MISSING}|Development|Piezo Slider Actuators}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 28 [ label = <{{#87 | MISSING}|Equipment|Diode Laser}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 29 [ label = <{{#86 | ASSIGNED}|Development|Optomechanical System}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 30 [ label = <{{#85 | ASSIGNED}|Development|Laser Diode Driver/Controller}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 31 [ label = <{{#84 | MISSING}|Equipment|Stabilized Helium-Neon Laser}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 32 [ label = <{{#83 | MISSING}|Equipment|External Cavity Diode Laser (ECDL)}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 33 [ label = <{{#82 | MISSING}|Equipment|Coherent Light Source}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 34 [ label = <{{#81 | MISSING}|Process|Interferometry}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 35 [ label = <{{#80 | MISSING}|Process|Plasma Cleaning}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 36 [ label = <{{#79 | MISSING}|Equipment|Sputter Coater}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 37 [ label = <{{#78 | ASSIGNED}|Process|Optical Die Imaging}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 38 [ label = <{{#77 | MISSING}|Process|Imaging of Human Blood Cells}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 39 [ label = <{{#76 | COMPLETED}|Process|Video Streaming}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 40 [ label = <{{#75 | COMPLETED}|Equipment|Microphone(s)}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 41 [ label = <{{#74 | COMPLETED}|Equipment|Camcorder}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 42 [ label = <{{#73 | COMPLETED}|Development|Main Camera Rig}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 43 [ label = <{{#72 | MISSING}|Process|STM Non-metallic imaging}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 44 [ label = <{{#71 | MISSING}|Research|STM Metal Pattern Deposition}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 45 [ label = <{{#70 | MISSING}|Research|STM Lithography}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 46 [ label = <{{#69 | MISSING}|Research|STM Surface Topography Manipulation}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 47 [ label = <{{#68 | ASSIGNED}|Equipment|Heating Stirrer}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 48 [ label = <{{#67 | ASSIGNED}|Equipment|Chemical Storage/Containment}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 49 [ label = <{{#66 | COMPLETED}|Process|Video Recording}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 50 [ label = <{{#65 | MISSING}|Process|Gas chromatography}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 51 [ label = <{{#64 | COMPLETED}|Equipment|FFF 3D-Printer}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 52 [ label = <{{#63 | ASSIGNED}|Equipment|OpenFlexure Delta Stage}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 53 [ label = <{{#62 | MISSING}|Process|Lithography}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 54 [ label = <{{#61 | MISSING}|Process|Zeloof Z1 process}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 55 [ label = <{{#60 | MISSING}|Process|Thermal diffusion doping}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 56 [ label = <{{#59 | MISSING}|Process|H₃PO₄/HNO₃/AcOH Etching of Aluminum}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 57 [ label = <{{#58 | MISSING}|Process|Pattern Al}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 58 [ label = <{{#57 | MISSING}|Process|Metal thin film deposition}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 59 [ label = <{{#56 | MISSING}|Process|PVD: Thermal Evaporation}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 60 [ label = <{{#55 | ASSIGNED}|Equipment|Tube Furnace}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 61 [ label = <{{#54 | MISSING}|Process|Si Thermal Oxidation}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 62 [ label = <{{#53 | MISSING}|Process|Pattern SiO₂}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 63 [ label = <{{#52 | MISSING}|Development|Maskless photolithography stepper}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 64 [ label = <{{#51 | MISSING}|Process|Maskless Photolithography}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 65 [ label = <{{#50 | MISSING}|Process|E-beam Lithography}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 66 [ label = <{{#49 | ASSIGNED}|Development|Spin Coater}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 67 [ label = <{{#48 | MISSING}|Process|STM Imaging Individual Atoms}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 68 [ label = <{{#47 | MISSING}|Process|STM Imaging@1nm}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 69 [ label = <{{#46 | MISSING}|Process|STM Imaging@10nm}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 70 [ label = <{{#45 | ASSIGNED}|Process|STM Imaging@100nm}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 71 [ label = <{{#44 | ASSIGNED}|Process|STM Imaging@1µm}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 72 [ label = <{{#43 | ASSIGNED}|Development|Scanning Tunneling Microscope (STM)}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 73 [ label = <{{#42 | COMPLETED}|Development|STM Vibration Isolation}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 74 [ label = <{{#41 | COMPLETED}|Process|Primitive Die Imaging}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 75 [ label = <{{#39 | ASSIGNED}|Development|OBI Lite}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 76 [ label = <{{#38 | MISSING}|Process|SEM Non-Metallic Imaging}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 77 [ label = <{{#37 | MISSING}|Process|PVD: Sputtering}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 78 [ label = <{{#36 | MISSING}|Process|Primitive Chip Imaging}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 79 [ label = <{{#35 | MISSING}|Equipment|SEM Beam Blanker}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 80 [ label = <{{#34 | COMPLETED}|Equipment|Open Beam Interface}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 81 [ label = <{{#33 | COMPLETED}|Equipment|SEM Vibration Isolation}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 82 [ label = <{{#32 | MISSING}|Process|SEM Imaging@10nm}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 83 [ label = <{{#31 | COMPLETED}|Process|SEM Imaging@100nm}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 84 [ label = <{{#30 | COMPLETED}|Process|SEM Imaging@1µm}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 85 [ label = <{{#29 | COMPLETED}|Process|SEM Imaging@10µm}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 86 [ label = <{{#28 | COMPLETED}|Equipment|Scanning Electron Microscope (SEM)}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 87 [ label = <{{#27 | ASSIGNED}|Equipment|Technical Ventilation}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 88 [ label = <{{#26 | COMPLETED}|Equipment|Water Cooling}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 89 [ label = <{{#25 | MISSING}|Equipment|Plasma Etcher}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 90 [ label = <{{#24 | COMPLETED}|Equipment|~3ph Power (below 10kW)}>, shape = "record", color = "#080", fontcolor = "#080", fillcolor = "#afa", style = "filled"] + 91 [ label = <{{#23 | ASSIGNED}|Equipment|Fume Hood}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 92 [ label = <{{#21 | MISSING}|Process|Reactive Ion Etching}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 93 [ label = <{{#20 | MISSING}|Process|Body Bias Injection}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 94 [ label = <{{#19 | MISSING}|Process|IC Fault Injection}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 95 [ label = <{{#18 | MISSING}|Research|SEM Fault Injection}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 96 [ label = <{{#17 | MISSING}|Process|SEM Nanoprobing/Live Analysis}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 97 [ label = <{{#16 | MISSING}|Process|Laser Fault Injection}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 98 [ label = <{{#15 | MISSING}|Process|Microprobing}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 99 [ label = <{{#14 | ASSIGNED}|Equipment|Optical Microscope}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 100 [ label = <{{#13 | MISSING}|Process|Full Chip Reverse Engineering}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 101 [ label = <{{#12 | MISSING}|Process|DASH Stain}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 102 [ label = <{{#11 | MISSING}|Process|Simple Chip Imaging}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 103 [ label = <{{#10 | ASSIGNED}|Equipment|SEM: Motorized Stage}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 104 [ label = <{{#9 | ASSIGNED}|Development|Optical Microscope: Motorized Stage}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 105 [ label = <{{#8 | MISSING}|Process|Plasma Etching}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 106 [ label = <{{#7 | MISSING}|Process|Laser Cutting}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 107 [ label = <{{#6 | MISSING}|Process|HNO₃/H₂SO₄ Decapping}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 108 [ label = <{{#5 | MISSING}|Process|BOE Etching of SiO₂}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 109 [ label = <{{#4 | ASSIGNED}|Equipment|Wet Lab (Chemistry)}>, shape = "record", color = "#a50", fontcolor = "#a50", fillcolor = "#ffa", style = "filled"] + 110 [ label = <{{#3 | MISSING}|Equipment|Lapping Machine}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#ffddc1", style = "filled"] + 111 [ label = <{{#2 | MISSING}|Process|Chip Delayering}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 112 [ label = <{{#1 | MISSING}|Process|Chip Decapping}>, shape = "record", color = "#800", fontcolor = "#800", fillcolor = "#fcc", style = "filled"] + 0 -> 10 [ ] + 0 -> 15 [ ] + 0 -> 54 [ ] + 1 -> 21 [ ] + 1 -> 94 [ ] + 1 -> 100 [ ] + 2 -> 39 [ ] + 2 -> 49 [ ] + 3 -> 38 [ ] + 3 -> 43 [ ] + 3 -> 46 [ ] + 3 -> 67 [ ] + 3 -> 76 [ ] + 3 -> 82 [ ] + 4 -> 48 [ ] + 9 -> 6 [ ] + 9 -> 8 [ ] + 10 -> 11 [ ] + 10 -> 12 [ ] + 12 -> 16 [ ] + 14 -> 36 [ ] + 15 -> 62 [ ] + 16 -> 13 [ ] + 16 -> 14 [ ] + 16 -> 35 [ ] + 16 -> 56 [ ] + 16 -> 66 [ ] + 16 -> 109 [ ] + 21 -> 26 [ ] + 25 -> 17 [ ] + 25 -> 18 [ ] + 25 -> 19 [ ] + 25 -> 20 [ ] + 25 -> 22 [ ] + 25 -> 23 [ ] + 25 -> 24 [ ] + 26 -> 110 [ ] + 27 -> 7 [ ] + 28 -> 30 [ ] + 29 -> 51 [ ] + 32 -> 28 [ ] + 33 -> 28 [ ] + 33 -> 31 [ ] + 33 -> 32 [ ] + 34 -> 29 [ ] + 34 -> 33 [ ] + 35 -> 89 [ ] + 37 -> 104 [ ] + 38 -> 76 [ ] + 38 -> 83 [ ] + 38 -> 109 [ ] + 39 -> 42 [ ] + 42 -> 40 [ ] + 42 -> 41 [ ] + 43 -> 58 [ ] + 43 -> 72 [ ] + 44 -> 72 [ ] + 45 -> 66 [ ] + 45 -> 72 [ ] + 46 -> 68 [ ] + 48 -> 87 [ ] + 49 -> 5 [ ] + 49 -> 42 [ ] + 50 -> 109 [ ] + 52 -> 51 [ ] + 53 -> 45 [ ] + 53 -> 64 [ ] + 53 -> 65 [ ] + 54 -> 55 [ ] + 54 -> 57 [ ] + 54 -> 62 [ ] + 54 -> 98 [ ] + 55 -> 60 [ ] + 55 -> 66 [ ] + 56 -> 109 [ ] + 57 -> 44 [ ] + 57 -> 53 [ ] + 57 -> 56 [ ] + 57 -> 58 [ ] + 58 -> 59 [ ] + 58 -> 77 [ ] + 61 -> 60 [ ] + 62 -> 53 [ ] + 62 -> 61 [ ] + 62 -> 92 [ ] + 62 -> 108 [ ] + 64 -> 63 [ ] + 64 -> 66 [ ] + 65 -> 66 [ ] + 65 -> 75 [ ] + 65 -> 79 [ ] + 67 -> 68 [ ] + 68 -> 69 [ ] + 69 -> 70 [ ] + 70 -> 71 [ ] + 71 -> 72 [ ] + 72 -> 27 [ ] + 72 -> 34 [ ] + 72 -> 73 [ ] + 74 -> 85 [ ] + 75 -> 80 [ ] + 76 -> 58 [ ] + 76 -> 86 [ ] + 77 -> 36 [ ] + 78 -> 74 [ ] + 78 -> 112 [ ] + 79 -> 86 [ ] + 80 -> 86 [ ] + 81 -> 86 [ ] + 82 -> 81 [ ] + 82 -> 83 [ ] + 83 -> 84 [ ] + 84 -> 85 [ ] + 85 -> 86 [ ] + 86 -> 88 [ ] + 89 -> 87 [ ] + 89 -> 90 [ ] + 91 -> 87 [ ] + 92 -> 89 [ ] + 93 -> 112 [ ] + 94 -> 93 [ ] + 94 -> 95 [ ] + 94 -> 97 [ ] + 94 -> 98 [ ] + 95 -> 79 [ ] + 95 -> 96 [ ] + 96 -> 103 [ ] + 96 -> 111 [ ] + 97 -> 104 [ ] + 97 -> 112 [ ] + 98 -> 27 [ ] + 98 -> 104 [ ] + 100 -> 37 [ ] + 100 -> 101 [ ] + 100 -> 102 [ ] + 101 -> 109 [ ] + 102 -> 78 [ ] + 102 -> 83 [ ] + 102 -> 103 [ ] + 102 -> 111 [ ] + 103 -> 86 [ ] + 104 -> 52 [ ] + 104 -> 99 [ ] + 105 -> 89 [ ] + 107 -> 109 [ ] + 108 -> 109 [ ] + 109 -> 47 [ ] + 109 -> 48 [ ] + 109 -> 87 [ ] + 109 -> 91 [ ] + 111 -> 92 [ ] + 111 -> 106 [ ] + 111 -> 108 [ ] + 111 -> 110 [ ] + 111 -> 112 [ ] + 112 -> 105 [ ] + 112 -> 106 [ ] + 112 -> 107 [ ] + 112 -> 110 [ ] + +} diff --git a/techtree.svg b/techtree.svg new file mode 100644 index 0000000..195092c --- /dev/null +++ b/techtree.svg @@ -0,0 +1,2322 @@ + + + + + + + + + +0 + +#115 + +MISSING + +Process + +Semiconductor Manufacturing + + + +10 + +#105 + +ASSIGNED + +Process + +Create a Backlit LCD Device + + + +0->10 + + + + + +15 + +#100 + +MISSING + +Process + +Etch fractals on wafers + + + +0->15 + + + + + +54 + +#61 + +MISSING + +Process + +Zeloof Z1 process + + + +0->54 + + + + + +1 + +#114 + +MISSING + +Process + +Semiconductor & Electronics Analysis + + + +21 + +#94 + +ASSIGNED + +Process + +PCB Reverse Engineering + + + +1->21 + + + + + +94 + +#19 + +MISSING + +Process + +IC Fault Injection + + + +1->94 + + + + + +100 + +#13 + +MISSING + +Process + +Full Chip Reverse Engineering + + + +1->100 + + + + + +2 + +#113 + +MISSING + +Process + +Science Communication + + + +39 + +#76 + +COMPLETED + +Process + +Video Streaming + + + +2->39 + + + + + +49 + +#66 + +COMPLETED + +Process + +Video Recording + + + +2->49 + + + + + +3 + +#112 + +MISSING + +Process + +Nanoscale Imaging + + + +38 + +#77 + +MISSING + +Process + +Imaging of Human Blood Cells + + + +3->38 + + + + + +43 + +#72 + +MISSING + +Process + +STM Non-metallic imaging + + + +3->43 + + + + + +46 + +#69 + +MISSING + +Research + +STM Surface Topography Manipulation + + + +3->46 + + + + + +67 + +#48 + +MISSING + +Process + +STM Imaging Individual Atoms + + + +3->67 + + + + + +76 + +#38 + +MISSING + +Process + +SEM Non-Metallic Imaging + + + +3->76 + + + + + +82 + +#32 + +MISSING + +Process + +SEM Imaging@10nm + + + +3->82 + + + + + +4 + +#111 + +MISSING + +Process + +LIN supply + + + +48 + +#67 + +ASSIGNED + +Equipment + +Chemical Storage/Containment + + + +4->48 + + + + + +9 + +#106 + +MISSING + +Process + +Electronics Distribution + + + +6 + +#109 + +MISSING + +Equipment + +Environmental Chamber + + + +9->6 + + + + + +8 + +#107 + +MISSING + +Process + +EMI Precompliance Testing + + + +9->8 + + + + + +25 + +#90 + +ASSIGNED + +Process + +PCB Repair & Rework + + + +17 + +#98 + +ASSIGNED + +Development + +Gridfinity-compatible JEDEC IC holders + + + +25->17 + + + + + +18 + +#97 + +COMPLETED + +Equipment + +PCB Rework Microscope + + + +25->18 + + + + + +19 + +#96 + +COMPLETED + +Equipment + +Soldering Station + + + +25->19 + + + + + +20 + +#95 + +MISSING + +Equipment + +Thermal Camera + + + +25->20 + + + + + +22 + +#93 + +COMPLETED + +Equipment + +HEPA Fume Extractor + + + +25->22 + + + + + +23 + +#92 + +COMPLETED + +Equipment + +Miscellaneous Tools for BGA Rework + + + +25->23 + + + + + +24 + +#91 + +COMPLETED + +Equipment + +Hot Air Rework Station + + + +25->24 + + + + + +50 + +#65 + +MISSING + +Process + +Gas chromatography + + + +109 + +#4 + +ASSIGNED + +Equipment + +Wet Lab (Chemistry) + + + +50->109 + + + + + +5 + +#110 + +ASSIGNED + +Equipment + +Local NAS/server + + + +7 + +#108 + +MISSING + +Development + +Piezo Driver + + + +11 + +#104 + +ASSIGNED + +Process + +Electroluminescence Foil + + + +10->11 + + + + + +12 + +#103 + +MISSING + +Process + +Create a Matrix LCD Device + + + +10->12 + + + + + +16 + +#99 + +ASSIGNED + +Process + +Create an LCD Device + + + +12->16 + + + + + +13 + +#102 + +ASSIGNED + +Research + +Acquire Liquid Crystal Fluid + + + +14 + +#101 + +MISSING + +Process + +Chemical Vapor Deposition + + + +36 + +#79 + +MISSING + +Equipment + +Sputter Coater + + + +14->36 + + + + + +62 + +#53 + +MISSING + +Process + +Pattern SiO₂ + + + +15->62 + + + + + +16->13 + + + + + +16->14 + + + + + +35 + +#80 + +MISSING + +Process + +Plasma Cleaning + + + +16->35 + + + + + +56 + +#59 + +MISSING + +Process + +H₃PO₄/HNO₃/AcOH Etching of Aluminum + + + +16->56 + + + + + +66 + +#49 + +ASSIGNED + +Development + +Spin Coater + + + +16->66 + + + + + +16->109 + + + + + +26 + +#89 + +ASSIGNED + +Process + +PCB Delayering + + + +21->26 + + + + + +110 + +#3 + +MISSING + +Equipment + +Lapping Machine + + + +26->110 + + + + + +27 + +#88 + +MISSING + +Development + +Piezo Slider Actuators + + + +27->7 + + + + + +28 + +#87 + +MISSING + +Equipment + +Diode Laser + + + +30 + +#85 + +ASSIGNED + +Development + +Laser Diode Driver/Controller + + + +28->30 + + + + + +29 + +#86 + +ASSIGNED + +Development + +Optomechanical System + + + +51 + +#64 + +COMPLETED + +Equipment + +FFF 3D-Printer + + + +29->51 + + + + + +31 + +#84 + +MISSING + +Equipment + +Stabilized Helium-Neon Laser + + + +32 + +#83 + +MISSING + +Equipment + +External Cavity Diode Laser (ECDL) + + + +32->28 + + + + + +33 + +#82 + +MISSING + +Equipment + +Coherent Light Source + + + +33->28 + + + + + +33->31 + + + + + +33->32 + + + + + +34 + +#81 + +MISSING + +Process + +Interferometry + + + +34->29 + + + + + +34->33 + + + + + +89 + +#25 + +MISSING + +Equipment + +Plasma Etcher + + + +35->89 + + + + + +37 + +#78 + +ASSIGNED + +Process + +Optical Die Imaging + + + +104 + +#9 + +ASSIGNED + +Development + +Optical Microscope: Motorized Stage + + + +37->104 + + + + + +38->76 + + + + + +83 + +#31 + +COMPLETED + +Process + +SEM Imaging@100nm + + + +38->83 + + + + + +38->109 + + + + + +42 + +#73 + +COMPLETED + +Development + +Main Camera Rig + + + +39->42 + + + + + +40 + +#75 + +COMPLETED + +Equipment + +Microphone(s) + + + +41 + +#74 + +COMPLETED + +Equipment + +Camcorder + + + +42->40 + + + + + +42->41 + + + + + +58 + +#57 + +MISSING + +Process + +Metal thin film deposition + + + +43->58 + + + + + +72 + +#43 + +ASSIGNED + +Development + +Scanning Tunneling Microscope (STM) + + + +43->72 + + + + + +44 + +#71 + +MISSING + +Research + +STM Metal Pattern Deposition + + + +44->72 + + + + + +45 + +#70 + +MISSING + +Research + +STM Lithography + + + +45->66 + + + + + +45->72 + + + + + +68 + +#47 + +MISSING + +Process + +STM Imaging@1nm + + + +46->68 + + + + + +47 + +#68 + +ASSIGNED + +Equipment + +Heating Stirrer + + + +87 + +#27 + +ASSIGNED + +Equipment + +Technical Ventilation + + + +48->87 + + + + + +49->5 + + + + + +49->42 + + + + + +52 + +#63 + +ASSIGNED + +Equipment + +OpenFlexure Delta Stage + + + +52->51 + + + + + +53 + +#62 + +MISSING + +Process + +Lithography + + + +53->45 + + + + + +64 + +#51 + +MISSING + +Process + +Maskless Photolithography + + + +53->64 + + + + + +65 + +#50 + +MISSING + +Process + +E-beam Lithography + + + +53->65 + + + + + +55 + +#60 + +MISSING + +Process + +Thermal diffusion doping + + + +54->55 + + + + + +57 + +#58 + +MISSING + +Process + +Pattern Al + + + +54->57 + + + + + +54->62 + + + + + +98 + +#15 + +MISSING + +Process + +Microprobing + + + +54->98 + + + + + +60 + +#55 + +ASSIGNED + +Equipment + +Tube Furnace + + + +55->60 + + + + + +55->66 + + + + + +56->109 + + + + + +57->44 + + + + + +57->53 + + + + + +57->56 + + + + + +57->58 + + + + + +59 + +#56 + +MISSING + +Process + +PVD: Thermal Evaporation + + + +58->59 + + + + + +77 + +#37 + +MISSING + +Process + +PVD: Sputtering + + + +58->77 + + + + + +61 + +#54 + +MISSING + +Process + +Si Thermal Oxidation + + + +61->60 + + + + + +62->53 + + + + + +62->61 + + + + + +92 + +#21 + +MISSING + +Process + +Reactive Ion Etching + + + +62->92 + + + + + +108 + +#5 + +MISSING + +Process + +BOE Etching of SiO₂ + + + +62->108 + + + + + +63 + +#52 + +MISSING + +Development + +Maskless photolithography stepper + + + +64->63 + + + + + +64->66 + + + + + +65->66 + + + + + +75 + +#39 + +ASSIGNED + +Development + +OBI Lite + + + +65->75 + + + + + +79 + +#35 + +MISSING + +Equipment + +SEM Beam Blanker + + + +65->79 + + + + + +67->68 + + + + + +69 + +#46 + +MISSING + +Process + +STM Imaging@10nm + + + +68->69 + + + + + +70 + +#45 + +ASSIGNED + +Process + +STM Imaging@100nm + + + +69->70 + + + + + +71 + +#44 + +ASSIGNED + +Process + +STM Imaging@1µm + + + +70->71 + + + + + +71->72 + + + + + +72->27 + + + + + +72->34 + + + + + +73 + +#42 + +COMPLETED + +Development + +STM Vibration Isolation + + + +72->73 + + + + + +74 + +#41 + +COMPLETED + +Process + +Primitive Die Imaging + + + +85 + +#29 + +COMPLETED + +Process + +SEM Imaging@10µm + + + +74->85 + + + + + +80 + +#34 + +COMPLETED + +Equipment + +Open Beam Interface + + + +75->80 + + + + + +76->58 + + + + + +86 + +#28 + +COMPLETED + +Equipment + +Scanning Electron Microscope (SEM) + + + +76->86 + + + + + +77->36 + + + + + +78 + +#36 + +MISSING + +Process + +Primitive Chip Imaging + + + +78->74 + + + + + +112 + +#1 + +MISSING + +Process + +Chip Decapping + + + +78->112 + + + + + +79->86 + + + + + +80->86 + + + + + +81 + +#33 + +COMPLETED + +Equipment + +SEM Vibration Isolation + + + +81->86 + + + + + +82->81 + + + + + +82->83 + + + + + +84 + +#30 + +COMPLETED + +Process + +SEM Imaging@1µm + + + +83->84 + + + + + +84->85 + + + + + +85->86 + + + + + +88 + +#26 + +COMPLETED + +Equipment + +Water Cooling + + + +86->88 + + + + + +89->87 + + + + + +90 + +#24 + +COMPLETED + +Equipment + +~3ph Power (below 10kW) + + + +89->90 + + + + + +91 + +#23 + +ASSIGNED + +Equipment + +Fume Hood + + + +91->87 + + + + + +92->89 + + + + + +93 + +#20 + +MISSING + +Process + +Body Bias Injection + + + +93->112 + + + + + +94->93 + + + + + +95 + +#18 + +MISSING + +Research + +SEM Fault Injection + + + +94->95 + + + + + +97 + +#16 + +MISSING + +Process + +Laser Fault Injection + + + +94->97 + + + + + +94->98 + + + + + +95->79 + + + + + +96 + +#17 + +MISSING + +Process + +SEM Nanoprobing/Live Analysis + + + +95->96 + + + + + +103 + +#10 + +ASSIGNED + +Equipment + +SEM: Motorized Stage + + + +96->103 + + + + + +111 + +#2 + +MISSING + +Process + +Chip Delayering + + + +96->111 + + + + + +97->104 + + + + + +97->112 + + + + + +98->27 + + + + + +98->104 + + + + + +99 + +#14 + +ASSIGNED + +Equipment + +Optical Microscope + + + +100->37 + + + + + +101 + +#12 + +MISSING + +Process + +DASH Stain + + + +100->101 + + + + + +102 + +#11 + +MISSING + +Process + +Simple Chip Imaging + + + +100->102 + + + + + +101->109 + + + + + +102->78 + + + + + +102->83 + + + + + +102->103 + + + + + +102->111 + + + + + +103->86 + + + + + +104->52 + + + + + +104->99 + + + + + +105 + +#8 + +MISSING + +Process + +Plasma Etching + + + +105->89 + + + + + +106 + +#7 + +MISSING + +Process + +Laser Cutting + + + +107 + +#6 + +MISSING + +Process + +HNO₃/H₂SO₄ Decapping + + + +107->109 + + + + + +108->109 + + + + + +109->47 + + + + + +109->48 + + + + + +109->87 + + + + + +109->91 + + + + + +111->92 + + + + + +111->106 + + + + + +111->108 + + + + + +111->110 + + + + + +111->112 + + + + + +112->105 + + + + + +112->106 + + + + + +112->107 + + + + + +112->110 + + + + +