From f8b2cafb86c4cc731817973ecf75ca819467c150 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christina=20S=C3=B8rensen?= <christina@cafkafk.com>
Date: Sun, 22 Dec 2024 06:33:09 +0100
Subject: [PATCH] feat: kindergarten not done
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Christina Sørensen <christina@cafkafk.com>
---
 jq/kindergarten-garden/.exercism/config.json  |  19 +
 .../.exercism/metadata.json                   |   1 +
 jq/kindergarten-garden/HELP.md                | 114 ++++
 jq/kindergarten-garden/README.md              |  78 +++
 jq/kindergarten-garden/bats-extra.bash        | 637 ++++++++++++++++++
 jq/kindergarten-garden/bats-jq.bash           |  29 +
 jq/kindergarten-garden/kindergarten-garden.jq |   1 +
 .../test-kindergarten-garden.bats             | 259 +++++++
 8 files changed, 1138 insertions(+)
 create mode 100644 jq/kindergarten-garden/.exercism/config.json
 create mode 100644 jq/kindergarten-garden/.exercism/metadata.json
 create mode 100644 jq/kindergarten-garden/HELP.md
 create mode 100644 jq/kindergarten-garden/README.md
 create mode 100644 jq/kindergarten-garden/bats-extra.bash
 create mode 100644 jq/kindergarten-garden/bats-jq.bash
 create mode 100644 jq/kindergarten-garden/kindergarten-garden.jq
 create mode 100644 jq/kindergarten-garden/test-kindergarten-garden.bats

diff --git a/jq/kindergarten-garden/.exercism/config.json b/jq/kindergarten-garden/.exercism/config.json
new file mode 100644
index 0000000..ba7e7eb
--- /dev/null
+++ b/jq/kindergarten-garden/.exercism/config.json
@@ -0,0 +1,19 @@
+{
+  "authors": [
+    "glennj"
+  ],
+  "files": {
+    "solution": [
+      "kindergarten-garden.jq"
+    ],
+    "test": [
+      "test-kindergarten-garden.bats"
+    ],
+    "example": [
+      ".meta/example.jq"
+    ]
+  },
+  "blurb": "Given a diagram, determine which plants each child in the kindergarten class is responsible for.",
+  "source": "Exercise by the JumpstartLab team for students at The Turing School of Software and Design.",
+  "source_url": "https://turing.edu"
+}
diff --git a/jq/kindergarten-garden/.exercism/metadata.json b/jq/kindergarten-garden/.exercism/metadata.json
new file mode 100644
index 0000000..98cb2ed
--- /dev/null
+++ b/jq/kindergarten-garden/.exercism/metadata.json
@@ -0,0 +1 @@
+{"track":"jq","exercise":"kindergarten-garden","id":"91d42a711a514e69a85c3015fc5d0f26","url":"https://exercism.org/tracks/jq/exercises/kindergarten-garden","handle":"cafkafk","is_requester":true,"auto_approve":false}
\ No newline at end of file
diff --git a/jq/kindergarten-garden/HELP.md b/jq/kindergarten-garden/HELP.md
new file mode 100644
index 0000000..9131010
--- /dev/null
+++ b/jq/kindergarten-garden/HELP.md
@@ -0,0 +1,114 @@
+# Help
+
+## Running the tests
+
+Each exercise contains a test file.
+Run the tests using the `bats` program.
+
+```bash
+bats test-hello-world.bats
+```
+
+`bats` will need to be installed.
+See the [Testing on the Bash track][bash] page for instructions to install `bats` for your system.
+
+### bats is implemented in bash
+
+The bats file is a bash script, with some special functions recognized by the `bats` command.
+You'll see some tests that look like
+
+```sh
+jq -f some-exercise.jq <<< "{some,json,here}"
+```
+
+That `<<<` syntax is a bash [Here String][here-string].
+It sends the string on the right-hand side into the standard input of the program on the left-hand side.
+It is ([approximately][so]) the same as
+
+```sh
+echo "{some,json,here}" | jq -f some-exercise.jq
+```
+
+## Help for assert functions
+
+The tests use functions from the [bats-assert][bats-assert] library.
+Help for the various `assert*` functions can be found there.
+
+## Skipped tests
+
+Solving an exercise means making all its tests pass.
+By default, only one test (the first one) is executed when you run the tests.
+This is intentional, as it allows you to focus on just making that one test pass.
+Once it passes, you can enable the next test by commenting out or removing the
+
+    [[ $BATS_RUN_SKIPPED == true ]] || skip
+
+annotations prepending other tests.
+
+## Overriding skips
+
+To run all tests, including the ones with `skip` annotations, you can run:
+
+```bash
+BATS_RUN_SKIPPED=true bats test-some-exercise.bats
+```
+
+It can be convenient to use a wrapper function to save on typing: in `bash` you can do:
+
+```bash
+bats() {
+    BATS_RUN_SKIPPED=true command bats *.bats
+}
+```
+
+Then run tests with just:
+
+```bash
+bats
+```
+
+## Debugging in `jq`
+
+`jq` comes with a handy [`debug`][debug] filter.
+Use it while you are developing your exercise solutions to inspect the data that is currently in the jq pipline.
+See the [debugging doc][debugging] for more details.
+
+
+[bash]: https://exercism.org/docs/tracks/bash/tests
+[bats-assert]: https://github.com/bats-core/bats-assert
+[here-string]: https://www.gnu.org/software/bash/manual/bash.html#Here-Strings
+[so]: https://unix.stackexchange.com/a/80372/4667
+[debug]: https://jqlang.github.io/jq/manual/v1.7/#debug
+[debugging]: https://exercism.org/docs/tracks/jq/debugging
+
+## Submitting your solution
+
+You can submit your solution using the `exercism submit kindergarten-garden.jq` command.
+This command will upload your solution to the Exercism website and print the solution page's URL.
+
+It's possible to submit an incomplete solution which allows you to:
+
+- See how others have completed the exercise
+- Request help from a mentor
+
+## Need to get help?
+
+If you'd like help solving the exercise, check the following pages:
+
+- The [jq track's documentation](https://exercism.org/docs/tracks/jq)
+- The [jq track's programming category on the forum](https://forum.exercism.org/c/programming/jq)
+- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
+- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
+
+Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
+
+## Need more help?
+
+- Go to the [Exercism Community forum](https://forum.exercism.org) to get support and ask questions (or just chat!)
+  - Use the [Exercism Support](https://forum.exercism.org/c/support/8) category if you face any issues with working in the web editor, or downloading or submitting your exercises locally.
+  - Use the [Programming:jq](https://forum.exercism.org/c/programming/jq/133) category for jq-specific topics.
+- Join the community on [Exercism's Discord server](https://exercism.org/r/discord).
+- [StackOverflow](https://stackoverflow.com/questions/tagged/jq) can be used to search for your problem and see if it has been answered already.
+  You can also ask and answer questions.
+- [Github issue tracker](https://github.com/exercism/jq/issues) is where we track our development and maintainance of `jq` exercises in exercism.
+  If none of the above links help you, feel free to post an issue here.
\ No newline at end of file
diff --git a/jq/kindergarten-garden/README.md b/jq/kindergarten-garden/README.md
new file mode 100644
index 0000000..57ffe62
--- /dev/null
+++ b/jq/kindergarten-garden/README.md
@@ -0,0 +1,78 @@
+# Kindergarten Garden
+
+Welcome to Kindergarten Garden on Exercism's jq Track.
+If you need help running the tests or submitting your code, check out `HELP.md`.
+
+## Introduction
+
+The kindergarten class is learning about growing plants.
+The teacher thought it would be a good idea to give the class seeds to plant and grow in the dirt.
+To this end, the children have put little cups along the window sills and planted one type of plant in each cup.
+The children got to pick their favorites from four available types of seeds: grass, clover, radishes, and violets.
+
+## Instructions
+
+Your task is to, given a diagram, determine which plants each child in the kindergarten class is responsible for.
+
+There are 12 children in the class:
+
+- Alice, Bob, Charlie, David, Eve, Fred, Ginny, Harriet, Ileana, Joseph, Kincaid, and Larry.
+
+Four different types of seeds are planted:
+
+| Plant  | Diagram encoding |
+| ------ | ---------------- |
+| Grass  | G                |
+| Clover | C                |
+| Radish | R                |
+| Violet | V                |
+
+Each child gets four cups, two on each row:
+
+```text
+[window][window][window]
+........................ # each dot represents a cup
+........................
+```
+
+Their teacher assigns cups to the children alphabetically by their names, which means that Alice comes first and Larry comes last.
+
+Here is an example diagram representing Alice's plants:
+
+```text
+[window][window][window]
+VR......................
+RG......................
+```
+
+In the first row, nearest the windows, she has a violet and a radish.
+In the second row she has a radish and some grass.
+
+Your program will be given the plants from left-to-right starting with the row nearest the windows.
+From this, it should be able to determine which plants belong to each student.
+
+For example, if it's told that the garden looks like so:
+
+```text
+[window][window][window]
+VRCGVVRVCGGCCGVRGCVCGCGV
+VRCCCGCRRGVCGCRVVCVGCGCV
+```
+
+Then if asked for Alice's plants, it should provide:
+
+- Violets, radishes, violets, radishes
+
+While asking for Bob's plants would yield:
+
+- Clover, grass, clover, clover
+
+## Source
+
+### Created by
+
+- @glennj
+
+### Based on
+
+Exercise by the JumpstartLab team for students at The Turing School of Software and Design. - https://turing.edu
\ No newline at end of file
diff --git a/jq/kindergarten-garden/bats-extra.bash b/jq/kindergarten-garden/bats-extra.bash
new file mode 100644
index 0000000..54d4807
--- /dev/null
+++ b/jq/kindergarten-garden/bats-extra.bash
@@ -0,0 +1,637 @@
+# This is the source code for bats-support and bats-assert, concatenated
+# * https://github.com/bats-core/bats-support
+# * https://github.com/bats-core/bats-assert
+#
+# Comments have been removed to save space. See the git repos for full source code.
+
+############################################################
+#
+# bats-support - Supporting library for Bats test helpers
+#
+# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
+#
+# To the extent possible under law, the author(s) have dedicated all
+# copyright and related and neighboring rights to this software to the
+# public domain worldwide. This software is distributed without any
+# warranty.
+#
+# You should have received a copy of the CC0 Public Domain Dedication
+# along with this software. If not, see
+# <http://creativecommons.org/publicdomain/zero/1.0/>.
+#
+
+fail() {
+  (( $# == 0 )) && batslib_err || batslib_err "$@"
+  return 1
+}
+
+batslib_is_caller() {
+  local -i is_mode_direct=1
+
+  # Handle options.
+  while (( $# > 0 )); do
+    case "$1" in
+      -i|--indirect) is_mode_direct=0; shift ;;
+      --) shift; break ;;
+      *) break ;;
+    esac
+  done
+
+  # Arguments.
+  local -r func="$1"
+
+  # Check call stack.
+  if (( is_mode_direct )); then
+    [[ $func == "${FUNCNAME[2]}" ]] && return 0
+  else
+    local -i depth
+    for (( depth=2; depth<${#FUNCNAME[@]}; ++depth )); do
+      [[ $func == "${FUNCNAME[$depth]}" ]] && return 0
+    done
+  fi
+
+  return 1
+}
+
+batslib_err() {
+  { if (( $# > 0 )); then
+      echo "$@"
+    else
+      cat -
+    fi
+  } >&2
+}
+
+batslib_count_lines() {
+  local -i n_lines=0
+  local line
+  while IFS='' read -r line || [[ -n $line ]]; do
+    (( ++n_lines ))
+  done < <(printf '%s' "$1")
+  echo "$n_lines"
+}
+
+batslib_is_single_line() {
+  for string in "$@"; do
+    (( $(batslib_count_lines "$string") > 1 )) && return 1
+  done
+  return 0
+}
+
+batslib_get_max_single_line_key_width() {
+  local -i max_len=-1
+  while (( $# != 0 )); do
+    local -i key_len="${#1}"
+    batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len"
+    shift 2
+  done
+  echo "$max_len"
+}
+
+batslib_print_kv_single() {
+  local -ir col_width="$1"; shift
+  while (( $# != 0 )); do
+    printf '%-*s : %s\n' "$col_width" "$1" "$2"
+    shift 2
+  done
+}
+
+batslib_print_kv_multi() {
+  while (( $# != 0 )); do
+    printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )"
+    printf '%s\n' "$2"
+    shift 2
+  done
+}
+
+batslib_print_kv_single_or_multi() {
+  local -ir width="$1"; shift
+  local -a pairs=( "$@" )
+
+  local -a values=()
+  local -i i
+  for (( i=1; i < ${#pairs[@]}; i+=2 )); do
+    values+=( "${pairs[$i]}" )
+  done
+
+  if batslib_is_single_line "${values[@]}"; then
+    batslib_print_kv_single "$width" "${pairs[@]}"
+  else
+    local -i i
+    for (( i=1; i < ${#pairs[@]}; i+=2 )); do
+      pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )"
+    done
+    batslib_print_kv_multi "${pairs[@]}"
+  fi
+}
+
+batslib_prefix() {
+  local -r prefix="${1:-  }"
+  local line
+  while IFS='' read -r line || [[ -n $line ]]; do
+    printf '%s%s\n' "$prefix" "$line"
+  done
+}
+
+batslib_mark() {
+  local -r symbol="$1"; shift
+  # Sort line numbers.
+  set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" )
+
+  local line
+  local -i idx=0
+  while IFS='' read -r line || [[ -n $line ]]; do
+    if (( ${1:--1} == idx )); then
+      printf '%s\n' "${symbol}${line:${#symbol}}"
+      shift
+    else
+      printf '%s\n' "$line"
+    fi
+    (( ++idx ))
+  done
+}
+
+batslib_decorate() {
+  echo
+  echo "-- $1 --"
+  cat -
+  echo '--'
+  echo
+}
+
+############################################################
+
+assert() {
+  if ! "$@"; then
+    batslib_print_kv_single 10 'expression' "$*" \
+    | batslib_decorate 'assertion failed' \
+    | fail
+  fi
+}
+
+assert_equal() {
+  if [[ $1 != "$2" ]]; then
+    batslib_print_kv_single_or_multi 8 \
+    'expected' "$2" \
+    'actual'   "$1" \
+    | batslib_decorate 'values do not equal' \
+    | fail
+  fi
+}
+
+assert_failure() {
+  : "${output?}"
+  : "${status?}"
+
+  (( $# > 0 )) && local -r expected="$1"
+  if (( status == 0 )); then
+    batslib_print_kv_single_or_multi 6 'output' "$output" \
+    | batslib_decorate 'command succeeded, but it was expected to fail' \
+    | fail
+  elif (( $# > 0 )) && (( status != expected )); then
+    { local -ir width=8
+      batslib_print_kv_single "$width" \
+      'expected' "$expected" \
+      'actual'   "$status"
+      batslib_print_kv_single_or_multi "$width" \
+      'output' "$output"
+    } \
+    | batslib_decorate 'command failed as expected, but status differs' \
+    | fail
+  fi
+}
+
+assert_line() {
+  local -i is_match_line=0
+  local -i is_mode_partial=0
+  local -i is_mode_regexp=0
+  : "${lines?}"
+
+  # Handle options.
+  while (( $# > 0 )); do
+    case "$1" in
+    -n|--index)
+      if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then
+        echo "\`--index' requires an integer argument: \`$2'" \
+        | batslib_decorate 'ERROR: assert_line' \
+        | fail
+        return $?
+      fi
+      is_match_line=1
+      local -ri idx="$2"
+      shift 2
+      ;;
+    -p|--partial) is_mode_partial=1; shift ;;
+    -e|--regexp) is_mode_regexp=1; shift ;;
+    --) shift; break ;;
+    *) break ;;
+    esac
+  done
+
+  if (( is_mode_partial )) && (( is_mode_regexp )); then
+    echo "\`--partial' and \`--regexp' are mutually exclusive" \
+    | batslib_decorate 'ERROR: assert_line' \
+    | fail
+    return $?
+  fi
+
+  # Arguments.
+  local -r expected="$1"
+
+  if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then
+    echo "Invalid extended regular expression: \`$expected'" \
+    | batslib_decorate 'ERROR: assert_line' \
+    | fail
+    return $?
+  fi
+
+  # Matching.
+  if (( is_match_line )); then
+    # Specific line.
+    if (( is_mode_regexp )); then
+      if ! [[ ${lines[$idx]} =~ $expected ]]; then
+        batslib_print_kv_single 6 \
+        'index' "$idx" \
+        'regexp' "$expected" \
+        'line'  "${lines[$idx]}" \
+        | batslib_decorate 'regular expression does not match line' \
+        | fail
+      fi
+    elif (( is_mode_partial )); then
+      if [[ ${lines[$idx]} != *"$expected"* ]]; then
+        batslib_print_kv_single 9 \
+        'index'     "$idx" \
+        'substring' "$expected" \
+        'line'      "${lines[$idx]}" \
+        | batslib_decorate 'line does not contain substring' \
+        | fail
+      fi
+    else
+      if [[ ${lines[$idx]} != "$expected" ]]; then
+        batslib_print_kv_single 8 \
+        'index'    "$idx" \
+        'expected' "$expected" \
+        'actual'   "${lines[$idx]}" \
+        | batslib_decorate 'line differs' \
+        | fail
+      fi
+    fi
+  else
+    # Contained in output.
+    if (( is_mode_regexp )); then
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        [[ ${lines[$idx]} =~ $expected ]] && return 0
+      done
+      { local -ar single=( 'regexp' "$expected" )
+        local -ar may_be_multi=( 'output' "$output" )
+        local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+        batslib_print_kv_single "$width" "${single[@]}"
+        batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
+      } \
+      | batslib_decorate 'no output line matches regular expression' \
+      | fail
+    elif (( is_mode_partial )); then
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        [[ ${lines[$idx]} == *"$expected"* ]] && return 0
+      done
+      { local -ar single=( 'substring' "$expected" )
+        local -ar may_be_multi=( 'output' "$output" )
+        local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+        batslib_print_kv_single "$width" "${single[@]}"
+        batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
+      } \
+      | batslib_decorate 'no output line contains substring' \
+      | fail
+    else
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        [[ ${lines[$idx]} == "$expected" ]] && return 0
+      done
+      { local -ar single=( 'line' "$expected" )
+        local -ar may_be_multi=( 'output' "$output" )
+        local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+        batslib_print_kv_single "$width" "${single[@]}"
+        batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
+      } \
+      | batslib_decorate 'output does not contain line' \
+      | fail
+    fi
+  fi
+}
+
+assert_output() {
+  local -i is_mode_partial=0
+  local -i is_mode_regexp=0
+  local -i is_mode_nonempty=0
+  local -i use_stdin=0
+  : "${output?}"
+
+  # Handle options.
+  if (( $# == 0 )); then
+    is_mode_nonempty=1
+  fi
+
+  while (( $# > 0 )); do
+    case "$1" in
+    -p|--partial) is_mode_partial=1; shift ;;
+    -e|--regexp) is_mode_regexp=1; shift ;;
+    -|--stdin) use_stdin=1; shift ;;
+    --) shift; break ;;
+    *) break ;;
+    esac
+  done
+
+  if (( is_mode_partial )) && (( is_mode_regexp )); then
+    echo "\`--partial' and \`--regexp' are mutually exclusive" \
+    | batslib_decorate 'ERROR: assert_output' \
+    | fail
+    return $?
+  fi
+
+  # Arguments.
+  local expected
+  if (( use_stdin )); then
+    expected="$(cat -)"
+  else
+    expected="${1-}"
+  fi
+
+  # Matching.
+  if (( is_mode_nonempty )); then
+    if [ -z "$output" ]; then
+      echo 'expected non-empty output, but output was empty' \
+      | batslib_decorate 'no output' \
+      | fail
+    fi
+  elif (( is_mode_regexp )); then
+    if [[ '' =~ $expected ]] || (( $? == 2 )); then
+      echo "Invalid extended regular expression: \`$expected'" \
+      | batslib_decorate 'ERROR: assert_output' \
+      | fail
+    elif ! [[ $output =~ $expected ]]; then
+      batslib_print_kv_single_or_multi 6 \
+      'regexp'  "$expected" \
+      'output' "$output" \
+      | batslib_decorate 'regular expression does not match output' \
+      | fail
+    fi
+  elif (( is_mode_partial )); then
+    if [[ $output != *"$expected"* ]]; then
+      batslib_print_kv_single_or_multi 9 \
+      'substring' "$expected" \
+      'output'    "$output" \
+      | batslib_decorate 'output does not contain substring' \
+      | fail
+    fi
+  else
+    if [[ $output != "$expected" ]]; then
+      batslib_print_kv_single_or_multi 8 \
+      'expected' "$expected" \
+      'actual'   "$output" \
+      | batslib_decorate 'output differs' \
+      | fail
+    fi
+  fi
+}
+
+assert_success() {
+  : "${output?}"
+  : "${status?}"
+
+  if (( status != 0 )); then
+    { local -ir width=6
+      batslib_print_kv_single "$width" 'status' "$status"
+      batslib_print_kv_single_or_multi "$width" 'output' "$output"
+    } \
+    | batslib_decorate 'command failed' \
+    | fail
+  fi
+}
+
+refute() {
+  if "$@"; then
+    batslib_print_kv_single 10 'expression' "$*" \
+    | batslib_decorate 'assertion succeeded, but it was expected to fail' \
+    | fail
+  fi
+}
+
+refute_line() {
+  local -i is_match_line=0
+  local -i is_mode_partial=0
+  local -i is_mode_regexp=0
+  : "${lines?}"
+
+  # Handle options.
+  while (( $# > 0 )); do
+    case "$1" in
+    -n|--index)
+      if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then
+        echo "\`--index' requires an integer argument: \`$2'" \
+        | batslib_decorate 'ERROR: refute_line' \
+        | fail
+        return $?
+      fi
+      is_match_line=1
+      local -ri idx="$2"
+      shift 2
+      ;;
+    -p|--partial) is_mode_partial=1; shift ;;
+    -e|--regexp) is_mode_regexp=1; shift ;;
+    --) shift; break ;;
+    *) break ;;
+    esac
+  done
+
+  if (( is_mode_partial )) && (( is_mode_regexp )); then
+    echo "\`--partial' and \`--regexp' are mutually exclusive" \
+    | batslib_decorate 'ERROR: refute_line' \
+    | fail
+    return $?
+  fi
+
+  # Arguments.
+  local -r unexpected="$1"
+
+  if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
+    echo "Invalid extended regular expression: \`$unexpected'" \
+    | batslib_decorate 'ERROR: refute_line' \
+    | fail
+    return $?
+  fi
+
+  # Matching.
+  if (( is_match_line )); then
+    # Specific line.
+    if (( is_mode_regexp )); then
+      if [[ ${lines[$idx]} =~ $unexpected ]]; then
+        batslib_print_kv_single 6 \
+        'index' "$idx" \
+        'regexp' "$unexpected" \
+        'line'  "${lines[$idx]}" \
+        | batslib_decorate 'regular expression should not match line' \
+        | fail
+      fi
+    elif (( is_mode_partial )); then
+      if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
+        batslib_print_kv_single 9 \
+        'index'     "$idx" \
+        'substring' "$unexpected" \
+        'line'      "${lines[$idx]}" \
+        | batslib_decorate 'line should not contain substring' \
+        | fail
+      fi
+    else
+      if [[ ${lines[$idx]} == "$unexpected" ]]; then
+        batslib_print_kv_single 5 \
+        'index' "$idx" \
+        'line'  "${lines[$idx]}" \
+        | batslib_decorate 'line should differ' \
+        | fail
+      fi
+    fi
+  else
+    # Line contained in output.
+    if (( is_mode_regexp )); then
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        if [[ ${lines[$idx]} =~ $unexpected ]]; then
+          { local -ar single=( 'regexp' "$unexpected" 'index' "$idx" )
+            local -a may_be_multi=( 'output' "$output" )
+            local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+            batslib_print_kv_single "$width" "${single[@]}"
+            if batslib_is_single_line "${may_be_multi[1]}"; then
+              batslib_print_kv_single "$width" "${may_be_multi[@]}"
+            else
+              may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
+              batslib_print_kv_multi "${may_be_multi[@]}"
+            fi
+          } \
+          | batslib_decorate 'no line should match the regular expression' \
+          | fail
+          return $?
+        fi
+      done
+    elif (( is_mode_partial )); then
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
+          { local -ar single=( 'substring' "$unexpected" 'index' "$idx" )
+            local -a may_be_multi=( 'output' "$output" )
+            local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+            batslib_print_kv_single "$width" "${single[@]}"
+            if batslib_is_single_line "${may_be_multi[1]}"; then
+              batslib_print_kv_single "$width" "${may_be_multi[@]}"
+            else
+              may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
+              batslib_print_kv_multi "${may_be_multi[@]}"
+            fi
+          } \
+          | batslib_decorate 'no line should contain substring' \
+          | fail
+          return $?
+        fi
+      done
+    else
+      local -i idx
+      for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
+        if [[ ${lines[$idx]} == "$unexpected" ]]; then
+          { local -ar single=( 'line' "$unexpected" 'index' "$idx" )
+            local -a may_be_multi=( 'output' "$output" )
+            local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
+            batslib_print_kv_single "$width" "${single[@]}"
+            if batslib_is_single_line "${may_be_multi[1]}"; then
+              batslib_print_kv_single "$width" "${may_be_multi[@]}"
+            else
+              may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
+              batslib_print_kv_multi "${may_be_multi[@]}"
+            fi
+          } \
+          | batslib_decorate 'line should not be in output' \
+          | fail
+          return $?
+        fi
+      done
+    fi
+  fi
+}
+
+refute_output() {
+  local -i is_mode_partial=0
+  local -i is_mode_regexp=0
+  local -i is_mode_empty=0
+  local -i use_stdin=0
+  : "${output?}"
+
+  # Handle options.
+  if (( $# == 0 )); then
+    is_mode_empty=1
+  fi
+
+  while (( $# > 0 )); do
+    case "$1" in
+    -p|--partial) is_mode_partial=1; shift ;;
+    -e|--regexp) is_mode_regexp=1; shift ;;
+    -|--stdin) use_stdin=1; shift ;;
+    --) shift; break ;;
+    *) break ;;
+    esac
+  done
+
+  if (( is_mode_partial )) && (( is_mode_regexp )); then
+    echo "\`--partial' and \`--regexp' are mutually exclusive" \
+    | batslib_decorate 'ERROR: refute_output' \
+    | fail
+    return $?
+  fi
+
+  # Arguments.
+  local unexpected
+  if (( use_stdin )); then
+    unexpected="$(cat -)"
+  else
+    unexpected="${1-}"
+  fi
+
+  if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
+    echo "Invalid extended regular expression: \`$unexpected'" \
+    | batslib_decorate 'ERROR: refute_output' \
+    | fail
+    return $?
+  fi
+
+  # Matching.
+  if (( is_mode_empty )); then
+    if [ -n "$output" ]; then
+      batslib_print_kv_single_or_multi 6 \
+      'output' "$output" \
+      | batslib_decorate 'output non-empty, but expected no output' \
+      | fail
+    fi
+  elif (( is_mode_regexp )); then
+    if [[ $output =~ $unexpected ]]; then
+      batslib_print_kv_single_or_multi 6 \
+      'regexp'  "$unexpected" \
+      'output' "$output" \
+      | batslib_decorate 'regular expression should not match output' \
+      | fail
+    fi
+  elif (( is_mode_partial )); then
+    if [[ $output == *"$unexpected"* ]]; then
+      batslib_print_kv_single_or_multi 9 \
+      'substring' "$unexpected" \
+      'output'    "$output" \
+      | batslib_decorate 'output should not contain substring' \
+      | fail
+    fi
+  else
+    if [[ $output == "$unexpected" ]]; then
+      batslib_print_kv_single_or_multi 6 \
+      'output' "$output" \
+      | batslib_decorate 'output equals, but it was expected to differ' \
+      | fail
+    fi
+  fi
+}
diff --git a/jq/kindergarten-garden/bats-jq.bash b/jq/kindergarten-garden/bats-jq.bash
new file mode 100644
index 0000000..3f55da5
--- /dev/null
+++ b/jq/kindergarten-garden/bats-jq.bash
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+#
+# `bats-core` will consume both stdout and stderr for the `run` command's output.
+# However `jq` prints its DEBUG output on stderr.
+#
+# Lines starting with `["DEBUG:",` will be prefixed with a hash and printed on file descriptor 3.
+# Other lines on stderr will remain on stderr for bats to consume.
+#
+# See `bats-core` docs:
+# - "Printing to the terminal", https://bats-core.readthedocs.io/en/stable/writing-tests.html#printing-to-the-terminal
+# - "File descriptor 3", https://bats-core.readthedocs.io/en/stable/writing-tests.html#file-descriptor-3-read-this-if-bats-hangs
+
+
+jq() {
+    local output stderr rc line
+    stderr=$(mktemp)
+    output=$(command jq "$@" 2> "$stderr")
+    rc=$?
+    while IFS= read -r line || [[ -n $line ]]; do
+        if [[ $line == '["DEBUG:",'* ]]; then
+            echo "# $line" >&3
+        else
+            echo "$line" >&2
+        fi
+    done < "$stderr"
+    rm -f "$stderr"
+    echo "$output"
+    return "$rc"
+}
diff --git a/jq/kindergarten-garden/kindergarten-garden.jq b/jq/kindergarten-garden/kindergarten-garden.jq
new file mode 100644
index 0000000..6d0c541
--- /dev/null
+++ b/jq/kindergarten-garden/kindergarten-garden.jq
@@ -0,0 +1 @@
+"Remove this line and implement your solution" | halt_error
diff --git a/jq/kindergarten-garden/test-kindergarten-garden.bats b/jq/kindergarten-garden/test-kindergarten-garden.bats
new file mode 100644
index 0000000..37f28d9
--- /dev/null
+++ b/jq/kindergarten-garden/test-kindergarten-garden.bats
@@ -0,0 +1,259 @@
+#!/usr/bin/env bats
+# generated on 2024-07-23T22:14:38Z
+load bats-extra
+load bats-jq
+
+@test 'partial garden:garden with single student' {
+    #
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "RC\nGG",
+          "student": "Alice"
+        }
+END_INPUT
+
+    assert_success
+    expected='["radishes","clover","grass","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'partial garden:different garden with single student' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VC\nRC",
+          "student": "Alice"
+        }
+END_INPUT
+
+    assert_success
+    expected='["violets","clover","radishes","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'partial garden:garden with two students' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VVCG\nVVRC",
+          "student": "Bob"
+        }
+END_INPUT
+
+    assert_success
+    expected='["clover","grass","radishes","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'partial garden:multiple students for the same garden with three students:second student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VVCCGG\nVVCCGG",
+          "student": "Bob"
+        }
+END_INPUT
+
+    assert_success
+    expected='["clover","clover","clover","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'partial garden:multiple students for the same garden with three students:third student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VVCCGG\nVVCCGG",
+          "student": "Charlie"
+        }
+END_INPUT
+
+    assert_success
+    expected='["grass","grass","grass","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Alice, first student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Alice"
+        }
+END_INPUT
+
+    assert_success
+    expected='["violets","radishes","violets","radishes"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Bob, second student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Bob"
+        }
+END_INPUT
+
+    assert_success
+    expected='["clover","grass","clover","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Charlie' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Charlie"
+        }
+END_INPUT
+
+    assert_success
+    expected='["violets","violets","clover","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for David' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "David"
+        }
+END_INPUT
+
+    assert_success
+    expected='["radishes","violets","clover","radishes"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Eve' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Eve"
+        }
+END_INPUT
+
+    assert_success
+    expected='["clover","grass","radishes","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Fred' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Fred"
+        }
+END_INPUT
+
+    assert_success
+    expected='["grass","clover","violets","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Ginny' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Ginny"
+        }
+END_INPUT
+
+    assert_success
+    expected='["clover","grass","grass","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Harriet' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Harriet"
+        }
+END_INPUT
+
+    assert_success
+    expected='["violets","radishes","radishes","violets"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Ileana' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Ileana"
+        }
+END_INPUT
+
+    assert_success
+    expected='["grass","clover","violets","clover"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Joseph' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Joseph"
+        }
+END_INPUT
+
+    assert_success
+    expected='["violets","clover","violets","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Kincaid, second to last student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Kincaid"
+        }
+END_INPUT
+
+    assert_success
+    expected='["grass","clover","clover","grass"]'
+    assert_equal "$output" "$expected"
+}
+
+@test 'full garden:for Larry, last student'\''s garden' {
+
+
+    run jq -c -f kindergarten-garden.jq << 'END_INPUT'
+        {
+          "diagram": "VRCGVVRVCGGCCGVRGCVCGCGV\nVRCCCGCRRGVCGCRVVCVGCGCV",
+          "student": "Larry"
+        }
+END_INPUT
+
+    assert_success
+    expected='["grass","violets","clover","violets"]'
+    assert_equal "$output" "$expected"
+}