diff --git a/.gitignore b/.gitignore index f54094be..50dce689 100644 --- a/.gitignore +++ b/.gitignore @@ -479,3 +479,6 @@ target/ # Generated by nginx/ssl/generate-cert.sh -- never commit a private key. Programming/ERSMS-project/nginx/ssl/nginx.key Programming/ERSMS-project/nginx/ssl/nginx.crt + +# Output of ./run.sh run for the C++ courses. +build/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b4033e8a..8c508e6e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -63,9 +63,13 @@ repos: language: system files: \.(md|markdown)$ + # -x so shellcheck FOLLOWS sourced files. The 44 per-course run.sh stubs + # source scripts/course_lib.sh; without -x every one of them reports + # SC1091 "not following", and the only other way to silence that is a + # per-file disable, which is banned here. - id: shellcheck name: shellcheck - entry: bash -c 'printf "%s\0" "$@" | xargs -0 -n 40 shellcheck' -- + entry: bash -c 'printf "%s\0" "$@" | xargs -0 -n 40 shellcheck -x' -- language: system types: [shell] exclude_types: [zsh] diff --git a/DOCS-runnability.md b/DOCS-runnability.md index 365edbfb..06354bde 100644 --- a/DOCS-runnability.md +++ b/DOCS-runnability.md @@ -8,47 +8,47 @@ Unity and no .NET SDK. CI compares only its own column. | Course | local | Detail | |---|---|---| -| `NotProgramming/DPZ` | unprobed | no run.sh yet | -| `NotProgramming/ECOGR` | unprobed | no run.sh yet | -| `NotProgramming/EDABA` | unprobed | no run.sh yet | -| `NotProgramming/EDABA-LAB` | unprobed | no run.sh yet | -| `NotProgramming/EDISE` | unprobed | no run.sh yet | -| `NotProgramming/EDISP` | unprobed | no run.sh yet | -| `NotProgramming/ELAC` | unprobed | no run.sh yet | -| `NotProgramming/EMISY` | unprobed | no run.sh yet | -| `NotProgramming/ENUME` | unprobed | no run.sh yet | -| `NotProgramming/EPHY2` | unprobed | no run.sh yet | -| `NotProgramming/EPOGAI` | unprobed | no run.sh yet | -| `NotProgramming/ERPM` | unprobed | no run.sh yet | -| `NotProgramming/ESDP1` | unprobed | no run.sh yet | -| `NotProgramming/ESOEN` | unprobed | no run.sh yet | -| `NotProgramming/MOM` | unprobed | no run.sh yet | -| `NotProgramming/SDM` | unprobed | no run.sh yet | -| `NotProgramming/SDM2` | unprobed | no run.sh yet | -| `NotProgramming/SPD` | unprobed | no run.sh yet | -| `NotProgramming/STUP` | unprobed | no run.sh yet | -| `Programming/AIS` | unprobed | no run.sh yet | -| `Programming/BD2` | unprobed | no run.sh yet | -| `Programming/BSS` | unprobed | no run.sh yet | -| `Programming/EADS` | unprobed | no run.sh yet | -| `Programming/EARIN` | unprobed | no run.sh yet | -| `Programming/ECOAR` | unprobed | no run.sh yet | -| `Programming/ECOTE` | unprobed | no run.sh yet | -| `Programming/ECRYPT` | unprobed | no run.sh yet | -| `Programming/ECRYPT_PROJECT` | unprobed | no run.sh yet | -| `Programming/EGUI` | unprobed | no run.sh yet | -| `Programming/EOOP` | unprobed | no run.sh yet | -| `Programming/EOPSY` | unprobed | no run.sh yet | -| `Programming/EPFU` | unprobed | no run.sh yet | -| `Programming/E-PSYOPS` | unprobed | no run.sh yet | -| `Programming/ERSMS-project` | unprobed | no run.sh yet | -| `Programming/NLP` | unprobed | no run.sh yet | -| `Programming/PBAD` | unprobed | no run.sh yet | -| `Programming/PORR` | unprobed | no run.sh yet | -| `Programming/PSD` | unprobed | pre-existing run.sh, no --probe support | -| `Programming/psd_project` | unprobed | no run.sh yet | -| `Programming/TRAK` | unprobed | no run.sh yet | -| `Programming/twm_4` | unprobed | no run.sh yet | -| `Programming/USD` | unprobed | no run.sh yet | -| `Programming/WDWR` | unprobed | no run.sh yet | -| `Programming/ZPOB` | unprobed | no run.sh yet | +| `NotProgramming/DPZ` | runnable | builds the report with latexmk | +| `NotProgramming/ECOGR` | runnable | builds the report with latexmk | +| `NotProgramming/EDABA` | runnable | builds the report with latexmk | +| `NotProgramming/EDABA-LAB` | runnable | builds the report with latexmk | +| `NotProgramming/EDISE` | runnable | builds the report with latexmk | +| `NotProgramming/EDISP` | no-code | submitted lab reports as PDFs only; no source was produced | +| `NotProgramming/ELAC` | runnable | builds the report with latexmk | +| `NotProgramming/EMISY` | runnable | builds the report with latexmk | +| `NotProgramming/ENUME` | blocked | needs MATLAB or Octave (none of: matlab octave) | +| `NotProgramming/EPHY2` | no-code | submitted lab reports as PDFs only; no source was produced | +| `NotProgramming/EPOGAI` | no-code | a presentation only; no source was produced | +| `NotProgramming/ERPM` | runnable | builds the report with latexmk | +| `NotProgramming/ESDP1` | runnable | builds the report with latexmk | +| `NotProgramming/ESOEN` | runnable | builds the report with latexmk | +| `NotProgramming/MOM` | runnable | builds the report with latexmk | +| `NotProgramming/SDM` | runnable | builds the report with latexmk | +| `NotProgramming/SDM2` | runnable | builds the report with latexmk | +| `NotProgramming/SPD` | runnable | builds the report with latexmk | +| `NotProgramming/STUP` | runnable | npm install && npm start | +| `Programming/AIS` | runnable | builds the report with latexmk | +| `Programming/BD2` | runnable | npm install && npm start | +| `Programming/BSS` | runnable | builds the report with latexmk | +| `Programming/EADS` | runnable | compiles each standalone .cpp | +| `Programming/EARIN` | runnable | python3 the entry script | +| `Programming/ECOAR` | runnable | make | +| `Programming/ECOTE` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/ECOTE/program/code/main.py | +| `Programming/ECRYPT` | no-code | test1.py is a 0-byte stub; this course produced no submitted code | +| `Programming/ECRYPT_PROJECT` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/ECRYPT_PROJECT/code | +| `Programming/EGUI` | runnable | dotnet build | +| `Programming/EOOP` | runnable | compiles each standalone .cpp | +| `Programming/EOPSY` | runnable | make | +| `Programming/EPFU` | runnable | make | +| `Programming/E-PSYOPS` | runnable | opens in the Unity editor | +| `Programming/ERSMS-project` | runnable | docker compose up | +| `Programming/NLP` | runnable | python3 the entry script | +| `Programming/PBAD` | runnable | jupyter nbconvert --execute | +| `Programming/PORR` | runnable | python3 /home/kuhy/WUT_Computer_Science/Programming/PORR/code | +| `Programming/PSD` | runnable | starts the Kafka/Flink stack (installs packages with sudo) | +| `Programming/psd_project` | runnable | mvn package | +| `Programming/TRAK` | runnable | python3 the entry script | +| `Programming/twm_4` | runnable | jupyter nbconvert --execute | +| `Programming/USD` | no-code | README describes a MetaDrive RL assignment; no implementation was submitted | +| `Programming/WDWR` | runnable | python3 the entry script | +| `Programming/ZPOB` | runnable | builds the report with latexmk | diff --git a/NotProgramming/DPZ/run.sh b/NotProgramming/DPZ/run.sh new file mode 100755 index 00000000..03387c51 --- /dev/null +++ b/NotProgramming/DPZ/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/DPZ -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/ECOGR/run.sh b/NotProgramming/ECOGR/run.sh new file mode 100755 index 00000000..c9774fd4 --- /dev/null +++ b/NotProgramming/ECOGR/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ECOGR -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/EDABA-LAB/run.sh b/NotProgramming/EDABA-LAB/run.sh new file mode 100755 index 00000000..50d61dbc --- /dev/null +++ b/NotProgramming/EDABA-LAB/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/EDABA-LAB -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/EDABA/run.sh b/NotProgramming/EDABA/run.sh new file mode 100755 index 00000000..c7ce644c --- /dev/null +++ b/NotProgramming/EDABA/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/EDABA -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/EDISE/run.sh b/NotProgramming/EDISE/run.sh new file mode 100755 index 00000000..6639ac68 --- /dev/null +++ b/NotProgramming/EDISE/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/EDISE -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/EDISP/run.sh b/NotProgramming/EDISP/run.sh new file mode 100755 index 00000000..f21def47 --- /dev/null +++ b/NotProgramming/EDISP/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# NotProgramming/EDISP -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind none \ + --note "submitted lab reports as PDFs only; no source was produced" \ + -- "$@" diff --git a/NotProgramming/ELAC/run.sh b/NotProgramming/ELAC/run.sh new file mode 100755 index 00000000..e7651738 --- /dev/null +++ b/NotProgramming/ELAC/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ELAC -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/EMISY/run.sh b/NotProgramming/EMISY/run.sh new file mode 100755 index 00000000..a6c7e3f4 --- /dev/null +++ b/NotProgramming/EMISY/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/EMISY -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/ENUME/run.sh b/NotProgramming/ENUME/run.sh new file mode 100755 index 00000000..a700b055 --- /dev/null +++ b/NotProgramming/ENUME/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ENUME -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind matlab \ + -- "$@" diff --git a/NotProgramming/EPHY2/run.sh b/NotProgramming/EPHY2/run.sh new file mode 100755 index 00000000..659c8aa2 --- /dev/null +++ b/NotProgramming/EPHY2/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# NotProgramming/EPHY2 -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind none \ + --note "submitted lab reports as PDFs only; no source was produced" \ + -- "$@" diff --git a/NotProgramming/EPOGAI/run.sh b/NotProgramming/EPOGAI/run.sh new file mode 100755 index 00000000..d024f7b4 --- /dev/null +++ b/NotProgramming/EPOGAI/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# NotProgramming/EPOGAI -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind none \ + --note "a presentation only; no source was produced" \ + -- "$@" diff --git a/NotProgramming/ERPM/run.sh b/NotProgramming/ERPM/run.sh new file mode 100755 index 00000000..743548f6 --- /dev/null +++ b/NotProgramming/ERPM/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ERPM -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/ESDP1/run.sh b/NotProgramming/ESDP1/run.sh new file mode 100755 index 00000000..94837d28 --- /dev/null +++ b/NotProgramming/ESDP1/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ESDP1 -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/ESOEN/run.sh b/NotProgramming/ESOEN/run.sh new file mode 100755 index 00000000..adc65122 --- /dev/null +++ b/NotProgramming/ESOEN/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/ESOEN -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/MOM/run.sh b/NotProgramming/MOM/run.sh new file mode 100755 index 00000000..604b2c26 --- /dev/null +++ b/NotProgramming/MOM/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/MOM -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/SDM/run.sh b/NotProgramming/SDM/run.sh new file mode 100755 index 00000000..28653f68 --- /dev/null +++ b/NotProgramming/SDM/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/SDM -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/SDM2/run.sh b/NotProgramming/SDM2/run.sh new file mode 100755 index 00000000..b1d25148 --- /dev/null +++ b/NotProgramming/SDM2/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/SDM2 -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/SPD/run.sh b/NotProgramming/SPD/run.sh new file mode 100755 index 00000000..6dfb3ec2 --- /dev/null +++ b/NotProgramming/SPD/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# NotProgramming/SPD -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/NotProgramming/STUP/run.sh b/NotProgramming/STUP/run.sh new file mode 100755 index 00000000..c86a4bb7 --- /dev/null +++ b/NotProgramming/STUP/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# NotProgramming/STUP -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind node \ + --entry "$(dirname "$(readlink -f "$0")")/makieta" \ + -- "$@" diff --git a/Programming/AIS/run.sh b/Programming/AIS/run.sh new file mode 100755 index 00000000..a04a8164 --- /dev/null +++ b/Programming/AIS/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/AIS -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/Programming/BD2/run.sh b/Programming/BD2/run.sh new file mode 100755 index 00000000..71d49ab5 --- /dev/null +++ b/Programming/BD2/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/BD2 -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind node \ + --entry "$(dirname "$(readlink -f "$0")")/monorepo" \ + -- "$@" diff --git a/Programming/BSS/run.sh b/Programming/BSS/run.sh new file mode 100755 index 00000000..6d8e045d --- /dev/null +++ b/Programming/BSS/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/BSS -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/Programming/E-PSYOPS/run.sh b/Programming/E-PSYOPS/run.sh new file mode 100755 index 00000000..63be0f22 --- /dev/null +++ b/Programming/E-PSYOPS/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/E-PSYOPS -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind unity \ + -- "$@" diff --git a/Programming/EADS/MidTerm/task2.cpp b/Programming/EADS/MidTerm/task2.cpp index 863514f0..eb9bd414 100644 --- a/Programming/EADS/MidTerm/task2.cpp +++ b/Programming/EADS/MidTerm/task2.cpp @@ -1,55 +1,60 @@ -// Krzysztof Rudnicki, 307585 - -struct treeNode -{ - int key; - treeNode *left; - treeNode *right; -}; - -class Tree{ - - private: - treeNode *root; - public: - bool checkKeys(int givenKey); - bool findNode(treeNode*& nodeToFound, int givenKey); - int sumNodeSub(treeNode* start); -}; - -int Tree::sumNodeSub(const treeNode* start) -{ - return (sumNodeSub(start->right) - + sumNodeSub(start->left) - + start->key); -} - -bool Tree::findNode(treeNode*& nodeToFound, int givenKey); -{ - treeNode* curr = root; - treeNode* Cleft = curr->left; - treeNode* Cright = curr->right; - while(curr != nullptr) - { - if(curr -> key == givenKey) - { - nodeToFound = curr; - return 1; - }else - { - if(Cleft.findNode(nodeToFound, givenKey)) return 1; - if(Cright.findNode(nodeToFound, givenKey)) return 1; - } - } - return 0; -} - - - -bool Tree::checkKeys(int key) -{ - treeNode* start; - if (!findNode(start, key)) return 0; - // if we did not find the node we cannot compare the keys of it's left and right subtrees - return (sumNodeSub(start->left) > sumNodeSub(start->right)); +// Krzysztof Rudnicki, 307585 + +struct treeNode +{ + int key; + treeNode *left; + treeNode *right; +}; + +class Tree{ + + private: + treeNode *root; + public: + bool checkKeys(int givenKey); + bool findNode(treeNode*& nodeToFound, int givenKey); + static bool findNodeFrom(treeNode* curr, treeNode*& nodeToFound, int givenKey); + int sumNodeSub(const treeNode* start); +}; + +int Tree::sumNodeSub(const treeNode* start) +{ + // Without this the recursion has no base case and walks off the end of + // the tree; the declaration/definition const mismatch meant the body was + // never compiled, so it was never reached either. + if (start == nullptr) return 0; + return (sumNodeSub(start->right) + + sumNodeSub(start->left) + + start->key); +} + +// As submitted this did not compile: it called findNode on a treeNode*, which +// is a Tree method, and its while loop never advanced curr so it could not +// have terminated either. Same intent -- search the tree for a key -- expressed +// as the recursion the original was reaching for. +bool Tree::findNodeFrom(treeNode* curr, treeNode*& nodeToFound, int givenKey) +{ + if(curr == nullptr) return 0; + if(curr -> key == givenKey) + { + nodeToFound = curr; + return 1; + } + if(findNodeFrom(curr -> left, nodeToFound, givenKey)) return 1; + return findNodeFrom(curr -> right, nodeToFound, givenKey); +} + +bool Tree::findNode(treeNode*& nodeToFound, int givenKey) +{ + return findNodeFrom(root, nodeToFound, givenKey); +} + + +bool Tree::checkKeys(int key) +{ + treeNode* start; + if (!findNode(start, key)) return 0; + // if we did not find the node we cannot compare the keys of it's left and right subtrees + return (sumNodeSub(start->left) > sumNodeSub(start->right)); } \ No newline at end of file diff --git a/Programming/EADS/lab3.cpp b/Programming/EADS/lab3.cpp index 9f607752..f007f769 100644 --- a/Programming/EADS/lab3.cpp +++ b/Programming/EADS/lab3.cpp @@ -24,7 +24,7 @@ public: Node* getRoot() const; void destroy(Node* &someNode); ~Dictionary(); - void copyDictionary(Dictionary *&copiedDictRoot, Dictionary *otherTreeRoot); + void copyDictionary(Node *&copiedDictRoot, Node *otherTreeRoot); Dictionary(const Dictionary &other); void insert(const Key &newKey, const Info &newInfo); void remove(const Key &keyToRemove); @@ -67,13 +67,15 @@ template Dictionary::~Dictionary() { destroy(root); } template -void Dictionary::copyDictionary(Dictionary* &copiedDictRoot, Dictionary* otherDictRoot) +void Dictionary::copyDictionary(Node* &copiedDictRoot, Node* otherDictRoot) { if(otherDictRoot == nullptr) copiedDictRoot = nullptr; else { - copiedDictRoot = new Dictionary; + copiedDictRoot = new Node; + copiedDictRoot->key = otherDictRoot -> key; copiedDictRoot->info = otherDictRoot -> info; + copiedDictRoot->balanceFactor = otherDictRoot -> balanceFactor; copyDictionary(copiedDictRoot -> left, otherDictRoot -> left); copyDictionary(copiedDictRoot -> right, otherDictRoot -> right); } @@ -83,7 +85,7 @@ template Dictionary::Dictionary(const Dictionary &other) { if(other.root == nullptr) root = nullptr; - else copyTree(root, other.root); + else copyDictionary(root, other.root); } template diff --git a/Programming/EADS/run.sh b/Programming/EADS/run.sh new file mode 100755 index 00000000..6c16673d --- /dev/null +++ b/Programming/EADS/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/EADS -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind cxx \ + -- "$@" diff --git a/Programming/EARIN/run.sh b/Programming/EARIN/run.sh new file mode 100755 index 00000000..3d64a327 --- /dev/null +++ b/Programming/EARIN/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/EARIN -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + -- "$@" diff --git a/Programming/ECOAR/run.sh b/Programming/ECOAR/run.sh new file mode 100755 index 00000000..ad889548 --- /dev/null +++ b/Programming/ECOAR/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/ECOAR -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind make \ + --entry "$(dirname "$(readlink -f "$0")")/C" \ + -- "$@" diff --git a/Programming/ECOTE/run.sh b/Programming/ECOTE/run.sh new file mode 100755 index 00000000..2e0cb758 --- /dev/null +++ b/Programming/ECOTE/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/ECOTE -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + --entry "$(dirname "$(readlink -f "$0")")/program/code/main.py" \ + -- "$@" diff --git a/Programming/ECRYPT/run.sh b/Programming/ECRYPT/run.sh new file mode 100755 index 00000000..3cfd00f9 --- /dev/null +++ b/Programming/ECRYPT/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/ECRYPT -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind none \ + --note "test1.py is a 0-byte stub; this course produced no submitted code" \ + -- "$@" diff --git a/Programming/ECRYPT_PROJECT/run.sh b/Programming/ECRYPT_PROJECT/run.sh new file mode 100755 index 00000000..f441b9a5 --- /dev/null +++ b/Programming/ECRYPT_PROJECT/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/ECRYPT_PROJECT -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + --entry "$(dirname "$(readlink -f "$0")")/code" \ + -- "$@" diff --git a/Programming/EGUI/run.sh b/Programming/EGUI/run.sh new file mode 100755 index 00000000..e0bfcb5b --- /dev/null +++ b/Programming/EGUI/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/EGUI -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind dotnet \ + --entry "$(dirname "$(readlink -f "$0")")/lab2/lab2" \ + -- "$@" diff --git a/Programming/EOOP/run.sh b/Programming/EOOP/run.sh new file mode 100755 index 00000000..caf5c8ea --- /dev/null +++ b/Programming/EOOP/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/EOOP -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind cxx \ + -- "$@" diff --git a/Programming/EOPSY/run.sh b/Programming/EOPSY/run.sh new file mode 100755 index 00000000..93651780 --- /dev/null +++ b/Programming/EOPSY/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/EOPSY -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind make \ + --entry "$(dirname "$(readlink -f "$0")")/lab3/task3/ftp" \ + -- "$@" diff --git a/Programming/EPFU/run.sh b/Programming/EPFU/run.sh new file mode 100755 index 00000000..5f11d6fa --- /dev/null +++ b/Programming/EPFU/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/EPFU -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind make \ + --entry "$(dirname "$(readlink -f "$0")")/penguins/src" \ + -- "$@" diff --git a/Programming/ERSMS-project/run.sh b/Programming/ERSMS-project/run.sh new file mode 100755 index 00000000..a322d5d5 --- /dev/null +++ b/Programming/ERSMS-project/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/ERSMS-project -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind compose \ + -- "$@" diff --git a/Programming/NLP/run.sh b/Programming/NLP/run.sh new file mode 100755 index 00000000..e685812e --- /dev/null +++ b/Programming/NLP/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/NLP -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + -- "$@" diff --git a/Programming/PBAD/run.sh b/Programming/PBAD/run.sh new file mode 100755 index 00000000..8f1435af --- /dev/null +++ b/Programming/PBAD/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/PBAD -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind notebook \ + -- "$@" diff --git a/Programming/PORR/run.sh b/Programming/PORR/run.sh new file mode 100755 index 00000000..eb6f060e --- /dev/null +++ b/Programming/PORR/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/PORR -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + --entry "$(dirname "$(readlink -f "$0")")/code" \ + -- "$@" diff --git a/Programming/PSD/run.sh b/Programming/PSD/run.sh index 9bf28073..b4d69788 100755 --- a/Programming/PSD/run.sh +++ b/Programming/PSD/run.sh @@ -1,5 +1,21 @@ #!/bin/bash +# --probe: report whether this can run here WITHOUT running it, per the +# contract in ../../run.sh. This script is the original coursework runner and +# is deliberately left otherwise untouched, so the probe is a early exit +# rather than a rewrite -- it installs packages with sudo and starts Kafka, +# which is exactly what a probe must never trigger. +if [[ "${1:-}" == "--probe" ]]; then + for tool in python mvn java; do + if ! command -v "$tool" > /dev/null 2>&1; then + echo "needs $tool" + exit 78 + fi + done + echo "starts the Kafka/Flink stack (installs packages with sudo)" + exit 0 +fi + # Function to run a script in the background and save its PID run_script() { python "$1" & diff --git a/Programming/TRAK/run.sh b/Programming/TRAK/run.sh new file mode 100755 index 00000000..4ae9e700 --- /dev/null +++ b/Programming/TRAK/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/TRAK -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + -- "$@" diff --git a/Programming/USD/run.sh b/Programming/USD/run.sh new file mode 100755 index 00000000..6638d9d7 --- /dev/null +++ b/Programming/USD/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/USD -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind none \ + --note "README describes a MetaDrive RL assignment; no implementation was submitted" \ + -- "$@" diff --git a/Programming/WDWR/run.sh b/Programming/WDWR/run.sh new file mode 100755 index 00000000..6a12a776 --- /dev/null +++ b/Programming/WDWR/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/WDWR -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind python \ + -- "$@" diff --git a/Programming/ZPOB/run.sh b/Programming/ZPOB/run.sh new file mode 100755 index 00000000..0ad11059 --- /dev/null +++ b/Programming/ZPOB/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/ZPOB -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind tex \ + -- "$@" diff --git a/Programming/psd_project/run.sh b/Programming/psd_project/run.sh new file mode 100755 index 00000000..5e54ee33 --- /dev/null +++ b/Programming/psd_project/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Programming/psd_project -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind maven \ + --entry "$(dirname "$(readlink -f "$0")")/anomaly-detector" \ + -- "$@" diff --git a/Programming/twm_4/run.sh b/Programming/twm_4/run.sh new file mode 100755 index 00000000..a6280ffb --- /dev/null +++ b/Programming/twm_4/run.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Programming/twm_4 -- see ../../run.sh for the probe contract. +set -euo pipefail + +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../../scripts/course_lib.sh +. "$(dirname "$(readlink -f "$0")")/../../scripts/course_lib.sh" + +course_main --kind notebook \ + -- "$@" diff --git a/run.sh b/run.sh index b24d0cdd..2e26a599 100755 --- a/run.sh +++ b/run.sh @@ -45,6 +45,13 @@ cmd_check() { cmd_install() { exec "${SCRIPT_DIR}/install.sh" "$@"; } +# A runner opts in either by handling --probe itself, or by delegating to the +# shared library (which does). Anything else predates this harness and is left +# strictly alone. +_supports_probe() { + grep -qF -- '--probe' "$1" || grep -qF 'course_lib.sh' "$1" +} + # Probe one directory. Prints "\t"; never executes a project. # # The guard below is load-bearing. Some course dirs already ship their own @@ -56,7 +63,7 @@ cmd_install() { exec "${SCRIPT_DIR}/install.sh" "$@"; } # blocks on input anyway. probe_one() { local dir="$1" runner="$1/run.sh" - if [[ -x "$runner" ]] && grep -qF -- '--probe' "$runner"; then + if [[ -x "$runner" ]] && _supports_probe "$runner"; then local out status out="$(timeout 20s "$runner" --probe 2> /dev/null)" && status=0 || status=$? case "$status" in diff --git a/scripts/course_lib.sh b/scripts/course_lib.sh new file mode 100644 index 00000000..8b238f81 --- /dev/null +++ b/scripts/course_lib.sh @@ -0,0 +1,225 @@ +# shellcheck shell=bash +# Shared behaviour for every per-course run.sh. Sourced, never executed. +# +# A course run.sh is a stub: it declares what kind of project it is, then calls +# course_main. The logic lives here once, because 44 hand-copied runners is +# precisely how gates and scripts in this fleet have drifted apart before. +# +# Contract (see ../../run.sh): +# --probe report whether this could run HERE, without running it +# exit 0 runnable | 78 blocked | 79 nothing to run +# (no args) actually run it +# +# A stub calls: +# course_main --kind [--entry ] [--note ] -- "$@" +# Values are passed as arguments rather than set as globals so that a stub has +# no assignments a linter has to be told to ignore. + +readonly COURSE_EXIT_BLOCKED=78 +readonly COURSE_EXIT_NO_CODE=79 + +COURSE_ROOT="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[1]}")")" && pwd)" +readonly COURSE_ROOT + +# --- helpers ----------------------------------------------------------------- + +_have() { command -v "$1" > /dev/null 2>&1; } + +# Report "blocked" with the reason, which is the whole point of the status +# table: "needs X" is useful, "failed" is not. +_blocked() { + printf '%s\n' "$1" + exit "$COURSE_EXIT_BLOCKED" +} + +_no_code() { + printf '%s\n' "$1" + exit "$COURSE_EXIT_NO_CODE" +} + +_runnable() { printf '%s\n' "$1"; exit 0; } + +# First tool present wins; otherwise blocked naming all the candidates. +_require_any() { + local label="$1"; shift + local tool + for tool in "$@"; do + if _have "$tool"; then + printf '%s' "$tool" + return 0 + fi + done + _blocked "needs $label (none of: $*)" +} + +# Probe-side variant. _require_any prints the tool it found, so probes have to +# redirect its stdout -- which also swallowed the failure REASON and turned +# every blocked probe into "unknown". This one returns a status and prints +# only on failure. +_probe_any() { + local label="$1"; shift + local tool + for tool in "$@"; do + _have "$tool" && return 0 + done + _blocked "needs $label (none of: $*)" +} + +_first_file() { + find "$COURSE_ROOT" -name "$1" -not -path '*/node_modules/*' -print -quit 2>/dev/null +} + +# --- probes ------------------------------------------------------------------ + +_probe() { + case "$COURSE_KIND" in + none) _no_code "${COURSE_NOTE:-no executable code in this directory}" ;; + tex) + _probe_any "a LaTeX toolchain" latexmk pdflatex xelatex + _runnable "builds ${COURSE_ENTRY:-the report} with latexmk" + ;; + python) + _have python3 || _blocked "needs python3" + [[ -n "$(_first_file '*.py')" ]] || _no_code "no .py files found" + _runnable "python3 ${COURSE_ENTRY:-the entry script}" + ;; + node) + _have node || _blocked "needs node" + _have npm || _blocked "needs npm" + _runnable "npm install && npm start" + ;; + maven) + _have mvn || _blocked "needs maven" + _have java || _blocked "needs a JDK" + _runnable "mvn package" + ;; + make) + _have make || _blocked "needs make" + _probe_any "a C compiler" gcc cc clang + _runnable "make" + ;; + dotnet) + _have dotnet || _blocked "needs the .NET SDK" + _runnable "dotnet build" + ;; + unity) + _have unity-editor || _have unityhub \ + || _blocked "needs the Unity editor (GUI, not installable on a CI runner)" + _runnable "opens in the Unity editor" + ;; + matlab) + _probe_any "MATLAB or Octave" matlab octave + _runnable "runs the .m scripts" + ;; + cxx) + _probe_any "a C++ compiler" g++ clang++ + [[ -n "$(_first_file '*.cpp')" ]] || _no_code "no .cpp files found" + _runnable "compiles each standalone .cpp" + ;; + notebook) + _have jupyter || _blocked "needs jupyter" + _runnable "jupyter nbconvert --execute" + ;; + compose) + _have docker || _blocked "needs docker" + docker info > /dev/null 2>&1 || _blocked "docker is installed but the daemon is not running" + _runnable "docker compose up" + ;; + *) _blocked "unknown COURSE_KIND '${COURSE_KIND:-unset}'" ;; + esac +} + +# --- runners ----------------------------------------------------------------- + +_run() { + case "$COURSE_KIND" in + none) _no_code "${COURSE_NOTE:-nothing to run}" ;; + tex) + local tex="${COURSE_ENTRY:-}" + [[ -n "$tex" ]] || tex="$(_first_file '*.tex')" + [[ -n "$tex" ]] || _no_code "no .tex found" + local tool + tool="$(_require_any 'a LaTeX toolchain' latexmk pdflatex xelatex)" + if [[ $tool == latexmk ]]; then + ( cd "$(dirname "$tex")" && latexmk -pdf -interaction=nonstopmode "$(basename "$tex")" ) + else + ( cd "$(dirname "$tex")" && "$tool" -interaction=nonstopmode "$(basename "$tex")" ) + fi + ;; + python) + local entry="${COURSE_ENTRY:-}" + [[ -n "$entry" ]] || entry="$(_first_file 'main.py')" + [[ -n "$entry" ]] || _no_code "no entry point; see this directory's README" + ( cd "$(dirname "$entry")" && python3 "$(basename "$entry")" ) + ;; + node) ( cd "${COURSE_ENTRY:-$COURSE_ROOT}" && npm install && npm start ) ;; + maven) ( cd "${COURSE_ENTRY:-$COURSE_ROOT}" && mvn -q package ) ;; + make) ( cd "${COURSE_ENTRY:-$COURSE_ROOT}" && make ) ;; + dotnet) ( cd "${COURSE_ENTRY:-$COURSE_ROOT}" && dotnet build ) ;; + compose) ( cd "${COURSE_ENTRY:-$COURSE_ROOT}" && docker compose up ) ;; + unity) _blocked "open ${COURSE_ROOT} in the Unity editor; there is no headless path" ;; + cxx) + # Each .cpp here is a self-contained assignment with its own main(), + # so they are compiled individually rather than linked together. + local cxx src rel out + cxx="$(_require_any 'a C++ compiler' g++ clang++)" + # Binaries go to build/, which is gitignored -- compiling in place + # drops untracked executables next to the sources, and an + # extensionless binary is not something .gitignore catches by name. + mkdir -p "$COURSE_ROOT/build" + while IFS= read -r src; do + rel="${src#"$COURSE_ROOT"/}" + out="$COURSE_ROOT/build/$(basename "${rel%.cpp}")" + # Some files here are exam-answer fragments with no main(), so + # they cannot be linked. Compile those to an object instead -- + # that still type-checks them, which is the point. + if grep -qE '\bint[[:space:]]+main[[:space:]]*\(' "$src"; then + printf 'compiling %s\n' "$rel" + "$cxx" -O2 -o "$out" "$src" + else + printf 'checking %s (no main; -c only)\n' "$rel" + "$cxx" -O2 -c -o "${out}.o" "$src" + fi + done < <(find "$COURSE_ROOT" -name '*.cpp' -not -path '*/node_modules/*' -not -path '*/build/*' | sort) + printf 'binaries in %s/build\n' "$COURSE_ROOT" + ;; + notebook) + _have jupyter || _blocked "needs jupyter" + local nb + while IFS= read -r nb; do + jupyter nbconvert --to notebook --execute --inplace "$nb" + done < <(find "$COURSE_ROOT" -name '*.ipynb' -not -path '*/.ipynb_checkpoints/*' | sort) + ;; + matlab) + local tool + tool="$(_require_any 'MATLAB or Octave' matlab octave)" + printf 'run the .m files in %s with %s\n' "$COURSE_ROOT" "$tool" + ;; + *) printf 'unknown COURSE_KIND: %s\n' "${COURSE_KIND:-unset}" >&2; return 1 ;; + esac +} + +course_main() { + COURSE_KIND="" + COURSE_ENTRY="" + COURSE_NOTE="" + while [[ $# -gt 0 ]]; do + case "$1" in + --kind) COURSE_KIND="$2"; shift 2 ;; + --entry) COURSE_ENTRY="$2"; shift 2 ;; + --note) COURSE_NOTE="$2"; shift 2 ;; + --) shift; break ;; + *) break ;; + esac + done + + case "${1:-}" in + --probe) _probe ;; + -h | --help) + printf 'usage: %s [--probe]\n' "$(basename "$0")" + printf ' --probe report runnable/blocked/no-code without running\n' + ;; + "") _run ;; + *) printf 'unknown option: %s\n' "$1" >&2; return 1 ;; + esac +}