Help: update getHelp()

Help: update getHelp()

####################################################################
# Help.awk                                                         #
####################################################################

# Return version as a string.
function getVersion() {
    return Name " " Version
}

# Return a list of language codes as a string.
# Parameters:
#     displayName = "endonym" or "name"
function getReference(displayName) {
    if (displayName == "name")
        return "┌─────────────────────────────┬──────────────────────┬─────────────────┐\n" \
            "│ " Locale["af"]["name"] "           - " AnsiCode["bold"] "af" AnsiCode["no bold"] "    │ " Locale["el"]["name"] "          - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["mn"]["name"] "  - " AnsiCode["bold"] "mn" AnsiCode["no bold"] " │\n" \
            "│ " Locale["sq"]["name"] "            - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │ " Locale["gu"]["name"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ne"]["name"] "     - " AnsiCode["bold"] "ne" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ar"]["name"] "              - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "    │ " Locale["ht"]["name"] " - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["no"]["name"] "  - " AnsiCode["bold"] "no" AnsiCode["no bold"] " │\n" \
            "│ " Locale["hy"]["name"] "            - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "    │ " Locale["ha"]["name"] "          - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["fa"]["name"] "    - " AnsiCode["bold"] "fa" AnsiCode["no bold"] " │\n" \
            "│ " Locale["az"]["name"] "         - " AnsiCode["bold"] "az" AnsiCode["no bold"] "    │ " Locale["he"]["name"] "         - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["pl"]["name"] "     - " AnsiCode["bold"] "pl" AnsiCode["no bold"] " │\n" \
            "│ " Locale["eu"]["name"] "              - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "    │ " Locale["hi"]["name"] "          - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["pt"]["name"] " - " AnsiCode["bold"] "pt" AnsiCode["no bold"] " │\n" \
            "│ " Locale["be"]["name"] "          - " AnsiCode["bold"] "be" AnsiCode["no bold"] "    │ " Locale["hmn"]["name"] "          - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["pa"]["name"] "    - " AnsiCode["bold"] "pa" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bn"]["name"] "             - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "    │ " Locale["hu"]["name"] "      - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["ro"]["name"] "   - " AnsiCode["bold"] "ro" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bs"]["name"] "             - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "    │ " Locale["is"]["name"] "      - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["ru"]["name"] "    - " AnsiCode["bold"] "ru" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bg"]["name"] "           - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "    │ " Locale["ig"]["name"] "           - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sr"]["name"] "    - " AnsiCode["bold"] "sr" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ca"]["name"] "             - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "    │ " Locale["id"]["name"] "     - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["sk"]["name"] "     - " AnsiCode["bold"] "sk" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ceb"]["name"] "             - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] "   │ " Locale["ga"]["name"] "          - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["sl"]["name"] "  - " AnsiCode["bold"] "sl" AnsiCode["no bold"] " │\n" \
            "│ " Locale["zh-CN"]["name"] "  - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │ " Locale["it"]["name"] "        - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["name"] "     - " AnsiCode["bold"] "so" AnsiCode["no bold"] " │\n" \
            "│ " Locale["zh-TW"]["name"] " - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │ " Locale["ja"]["name"] "       - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["es"]["name"] "    - " AnsiCode["bold"] "es" AnsiCode["no bold"] " │\n" \
            "│ " Locale["hr"]["name"] "            - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "    │ " Locale["jv"]["name"] "       - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sw"]["name"] "    - " AnsiCode["bold"] "sw" AnsiCode["no bold"] " │\n" \
            "│ " Locale["cs"]["name"] "               - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "    │ " Locale["kn"]["name"] "        - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["sv"]["name"] "    - " AnsiCode["bold"] "sv" AnsiCode["no bold"] " │\n" \
            "│ " Locale["da"]["name"] "              - " AnsiCode["bold"] "da" AnsiCode["no bold"] "    │ " Locale["km"]["name"] "          - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["ta"]["name"] "      - " AnsiCode["bold"] "ta" AnsiCode["no bold"] " │\n" \
            "│ " Locale["nl"]["name"] "               - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │ " Locale["ko"]["name"] "         - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["name"] "     - " AnsiCode["bold"] "te" AnsiCode["no bold"] " │\n" \
            "│ " Locale["en"]["name"] "             - " AnsiCode["bold"] "en" AnsiCode["no bold"] "    │ " Locale["lo"]["name"] "            - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["th"]["name"] "       - " AnsiCode["bold"] "th" AnsiCode["no bold"] " │\n" \
            "│ " Locale["eo"]["name"] "           - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "    │ " Locale["la"]["name"] "          - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["tr"]["name"] "    - " AnsiCode["bold"] "tr" AnsiCode["no bold"] " │\n" \
            "│ " Locale["et"]["name"] "            - " AnsiCode["bold"] "et" AnsiCode["no bold"] "    │ " Locale["lv"]["name"] "        - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["name"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] " │\n" \
            "│ " Locale["tl"]["name"] "            - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │ " Locale["lt"]["name"] "     - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["ur"]["name"] "       - " AnsiCode["bold"] "ur" AnsiCode["no bold"] " │\n" \
            "│ " Locale["fi"]["name"] "             - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "    │ " Locale["mk"]["name"] "     - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["name"] " - " AnsiCode["bold"] "vi" AnsiCode["no bold"] " │\n" \
            "│ " Locale["fr"]["name"] "              - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "    │ " Locale["ms"]["name"] "          - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["cy"]["name"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] " │\n" \
            "│ " Locale["gl"]["name"] "            - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "    │ " Locale["mt"]["name"] "        - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["yi"]["name"] "    - " AnsiCode["bold"] "yi" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ka"]["name"] "            - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "    │ " Locale["mi"]["name"] "          - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["yo"]["name"] "     - " AnsiCode["bold"] "yo" AnsiCode["no bold"] " │\n" \
            "│ " Locale["de"]["name"] "              - " AnsiCode["bold"] "de" AnsiCode["no bold"] "    │ " Locale["mr"]["name"] "        - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["zu"]["name"] "       - " AnsiCode["bold"] "zu" AnsiCode["no bold"] " │\n" \
            "└─────────────────────────────┴──────────────────────┴─────────────────┘"
    else
        return "┌────────────────────┬────────────────────────┬─────────────────────┐\n" \
            "│ " Locale["af"]["display"] "    - " AnsiCode["bold"] "af" AnsiCode["no bold"] "  │ " Locale["hi"]["display"] "            - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["nl"]["display"] "  - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ar"]["display"] "      - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "  │ " Locale["hmn"]["display"] "            - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["no"]["display"] "       - " AnsiCode["bold"] "no" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["az"]["display"] " - " AnsiCode["bold"] "az" AnsiCode["no bold"] "  │ " Locale["hr"]["display"] "         - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "  │ " Locale["pa"]["display"] "       - " AnsiCode["bold"] "pa" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["be"]["display"] "   - " AnsiCode["bold"] "be" AnsiCode["no bold"] "  │ " Locale["ht"]["display"] "   - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["pl"]["display"] "      - " AnsiCode["bold"] "pl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bg"]["display"] "    - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "  │ " Locale["hu"]["display"] "           - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["pt"]["display"] "   - " AnsiCode["bold"] "pt" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bn"]["display"] "        - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "  │ " Locale["hy"]["display"] "          - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "  │ " Locale["ro"]["display"] "      - " AnsiCode["bold"] "ro" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bs"]["display"] "     - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "  │ " Locale["id"]["display"] " - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["ru"]["display"] "     - " AnsiCode["bold"] "ru" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ca"]["display"] "       - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "  │ " Locale["ig"]["display"] "             - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sk"]["display"] "  - " AnsiCode["bold"] "sk" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ceb"]["display"] "      - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] " │ " Locale["is"]["display"] "         - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["sl"]["display"] " - " AnsiCode["bold"] "sl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["cs"]["display"] "      - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "  │ " Locale["it"]["display"] "         - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["display"] "    - " AnsiCode["bold"] "so" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["cy"]["display"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] "  │ " Locale["ja"]["display"] "           - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["sq"]["display"] "       - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["da"]["display"] "        - " AnsiCode["bold"] "da" AnsiCode["no bold"] "  │ " Locale["jv"]["display"] "        - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sr"]["display"] "      - " AnsiCode["bold"] "sr" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["de"]["display"] "      - " AnsiCode["bold"] "de" AnsiCode["no bold"] "  │ " Locale["ka"]["display"] "          - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "  │ " Locale["sv"]["display"] "     - " AnsiCode["bold"] "sv" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["el"]["display"] "     - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["km"]["display"] "         - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["sw"]["display"] "   - " AnsiCode["bold"] "sw" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["en"]["display"] "      - " AnsiCode["bold"] "en" AnsiCode["no bold"] "  │ " Locale["kn"]["display"] "             - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["ta"]["display"] "        - " AnsiCode["bold"] "ta" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["eo"]["display"] "    - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "  │ " Locale["ko"]["display"] "           - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["display"] "       - " AnsiCode["bold"] "te" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["es"]["display"] "      - " AnsiCode["bold"] "es" AnsiCode["no bold"] "  │ " Locale["la"]["display"] "           - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["th"]["display"] "         - " AnsiCode["bold"] "th" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["et"]["display"] "        - " AnsiCode["bold"] "et" AnsiCode["no bold"] "  │ " Locale["lo"]["display"] "              - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["tl"]["display"] "     - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["eu"]["display"] "      - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "  │ " Locale["lt"]["display"] "         - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["tr"]["display"] "      - " AnsiCode["bold"] "tr" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fa"]["display"] "        - " AnsiCode["bold"] "fa" AnsiCode["no bold"] "  │ " Locale["lv"]["display"] "         - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["display"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fi"]["display"] "        - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "  │ " Locale["mi"]["display"] "            - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["ur"]["display"] "        - " AnsiCode["bold"] "ur" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fr"]["display"] "     - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "  │ " Locale["mk"]["display"] "       - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["display"] "  - " AnsiCode["bold"] "vi" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ga"]["display"] "      - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["mn"]["display"] "           - " AnsiCode["bold"] "mn" AnsiCode["no bold"] "  │ " Locale["yi"]["display"] "       - " AnsiCode["bold"] "yi" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["gl"]["display"] "       - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "  │ " Locale["mr"]["display"] "            - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["yo"]["display"] "      - " AnsiCode["bold"] "yo" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["gu"]["display"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ms"]["display"] "    - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["zh-CN"]["display"] "    - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ha"]["display"] "        - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["mt"]["display"] "            - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["zh-TW"]["display"] "    - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │\n" \
            "│ " Locale["he"]["display"] "        - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["ne"]["display"] "            - " AnsiCode["bold"] "ne" AnsiCode["no bold"] "  │ " Locale["zu"]["display"] "     - " AnsiCode["bold"] "zu" AnsiCode["no bold"] "    │\n" \
            "└────────────────────┴────────────────────────┴─────────────────────┘"
}

# Return help message as a string.
function getHelp() {
    return "Usage: " Command " [options] [source]:[target] [" AnsiCode["underline"] "text" AnsiCode["no underline"] "] ...\n" \
        "       " Command " [options] [source]:[target1]+[target2]+... [" AnsiCode["underline"] "text" AnsiCode["no underline"] "] ...\n\n" \
        "Options:\n" \
        "  " AnsiCode["bold"] "-V, -version" AnsiCode["no bold"] "\n    Print version and exit.\n" \
        "  " AnsiCode["bold"] "-H, -h, -help" AnsiCode["no bold"] "\n    Show this manual, or print this help message and exit.\n" \
        "  " AnsiCode["bold"] "-r, -reference" AnsiCode["no bold"] "\n    Print a list of languages (displayed in endonyms) and their ISO 639 codes for reference, and exit.\n" \
        "  " AnsiCode["bold"] "-R, -reference-english" AnsiCode["no bold"] "\n    Print a list of languages (displayed in English names) and their ISO 639 codes for reference, and exit.\n" \
        "  " AnsiCode["bold"] "-v, -verbose" AnsiCode["no bold"] "\n    Verbose mode. (default)\n" \
        "  " AnsiCode["bold"] "-b, -brief" AnsiCode["no bold"] "\n    Brief mode.\n" \
        "  " AnsiCode["bold"] "-w [num], -width [num]" AnsiCode["no bold"] "\n    Specify the screen width for padding when displaying right-to-left languages.\n" \
        "  " AnsiCode["bold"] "-p, -play" AnsiCode["no bold"] "\n    Listen to the translation.\n" \
        "  " AnsiCode["bold"] "-P [program], -player [program]" AnsiCode["no bold"] "\n    Specify the command-line audio player to use, and listen to the translation.\n" \
        "  " AnsiCode["bold"] "-I, -interactive" AnsiCode["no bold"] "\n    Start an interactive shell, invoking `rlwrap` whenever possible (unless `-no-rlwrap` is specified).\n" \
        "  " AnsiCode["bold"] "-no-rlwrap" AnsiCode["no bold"] "\n    Don't invoke `rlwrap` when starting an interactive shell with `-I`.\n" \
        "  " AnsiCode["bold"] "-E, -emacs" AnsiCode["no bold"] "\n    Start an interactive shell within GNU Emacs, invoking `emacs`.\n" \
        "  " AnsiCode["bold"] "-prompt [prompt_string]" AnsiCode["no bold"] "\n    Customize your prompt string in the interactive shell.\n" \
        "  " AnsiCode["bold"] "-prompt-color [color_code]" AnsiCode["no bold"] "\n    Customize your prompt color in the interactive shell.\n" \
        "  " AnsiCode["bold"] "-i [file], -input [file]" AnsiCode["no bold"] "\n    Specify the input file name.\n" \
        "  " AnsiCode["bold"] "-o [file], -output [file]" AnsiCode["no bold"] "\n    Specify the output file name.\n" \
        "  " AnsiCode["bold"] "-l [code], -lang [code]" AnsiCode["no bold"] "\n    Specify your own, native language (\"home/host language\").\n" \
        "  " AnsiCode["bold"] "-s [code], -source [code]" AnsiCode["no bold"] "\n    Specify the source language (language of the original text).\n" \
        "  " AnsiCode["bold"] "-t [codes], -target [codes]" AnsiCode["no bold"] "\n    Specify the target language(s) (language(s) of the translated text).\n" \
        "\nSee the man page " Command "(1) for more information."
}

####################################################################
# Help.awk                                                         #
####################################################################

# Return version as a string.
function getVersion() {
    return Name " " Version
}

# Return a list of language codes as a string.
# Parameters:
#     displayName = "endonym" or "name"
function getReference(displayName) {
    if (displayName == "name")
        return "┌─────────────────────────────┬──────────────────────┬─────────────────┐\n" \
            "│ " Locale["af"]["name"] "           - " AnsiCode["bold"] "af" AnsiCode["no bold"] "    │ " Locale["el"]["name"] "          - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["mn"]["name"] "  - " AnsiCode["bold"] "mn" AnsiCode["no bold"] " │\n" \
            "│ " Locale["sq"]["name"] "            - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │ " Locale["gu"]["name"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ne"]["name"] "     - " AnsiCode["bold"] "ne" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ar"]["name"] "              - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "    │ " Locale["ht"]["name"] " - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["no"]["name"] "  - " AnsiCode["bold"] "no" AnsiCode["no bold"] " │\n" \
            "│ " Locale["hy"]["name"] "            - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "    │ " Locale["ha"]["name"] "          - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["fa"]["name"] "    - " AnsiCode["bold"] "fa" AnsiCode["no bold"] " │\n" \
            "│ " Locale["az"]["name"] "         - " AnsiCode["bold"] "az" AnsiCode["no bold"] "    │ " Locale["he"]["name"] "         - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["pl"]["name"] "     - " AnsiCode["bold"] "pl" AnsiCode["no bold"] " │\n" \
            "│ " Locale["eu"]["name"] "              - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "    │ " Locale["hi"]["name"] "          - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["pt"]["name"] " - " AnsiCode["bold"] "pt" AnsiCode["no bold"] " │\n" \
            "│ " Locale["be"]["name"] "          - " AnsiCode["bold"] "be" AnsiCode["no bold"] "    │ " Locale["hmn"]["name"] "          - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["pa"]["name"] "    - " AnsiCode["bold"] "pa" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bn"]["name"] "             - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "    │ " Locale["hu"]["name"] "      - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["ro"]["name"] "   - " AnsiCode["bold"] "ro" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bs"]["name"] "             - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "    │ " Locale["is"]["name"] "      - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["ru"]["name"] "    - " AnsiCode["bold"] "ru" AnsiCode["no bold"] " │\n" \
            "│ " Locale["bg"]["name"] "           - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "    │ " Locale["ig"]["name"] "           - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sr"]["name"] "    - " AnsiCode["bold"] "sr" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ca"]["name"] "             - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "    │ " Locale["id"]["name"] "     - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["sk"]["name"] "     - " AnsiCode["bold"] "sk" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ceb"]["name"] "             - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] "   │ " Locale["ga"]["name"] "          - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["sl"]["name"] "  - " AnsiCode["bold"] "sl" AnsiCode["no bold"] " │\n" \
            "│ " Locale["zh-CN"]["name"] "  - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │ " Locale["it"]["name"] "        - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["name"] "     - " AnsiCode["bold"] "so" AnsiCode["no bold"] " │\n" \
            "│ " Locale["zh-TW"]["name"] " - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │ " Locale["ja"]["name"] "       - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["es"]["name"] "    - " AnsiCode["bold"] "es" AnsiCode["no bold"] " │\n" \
            "│ " Locale["hr"]["name"] "            - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "    │ " Locale["jv"]["name"] "       - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sw"]["name"] "    - " AnsiCode["bold"] "sw" AnsiCode["no bold"] " │\n" \
            "│ " Locale["cs"]["name"] "               - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "    │ " Locale["kn"]["name"] "        - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["sv"]["name"] "    - " AnsiCode["bold"] "sv" AnsiCode["no bold"] " │\n" \
            "│ " Locale["da"]["name"] "              - " AnsiCode["bold"] "da" AnsiCode["no bold"] "    │ " Locale["km"]["name"] "          - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["ta"]["name"] "      - " AnsiCode["bold"] "ta" AnsiCode["no bold"] " │\n" \
            "│ " Locale["nl"]["name"] "               - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │ " Locale["ko"]["name"] "         - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["name"] "     - " AnsiCode["bold"] "te" AnsiCode["no bold"] " │\n" \
            "│ " Locale["en"]["name"] "             - " AnsiCode["bold"] "en" AnsiCode["no bold"] "    │ " Locale["lo"]["name"] "            - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["th"]["name"] "       - " AnsiCode["bold"] "th" AnsiCode["no bold"] " │\n" \
            "│ " Locale["eo"]["name"] "           - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "    │ " Locale["la"]["name"] "          - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["tr"]["name"] "    - " AnsiCode["bold"] "tr" AnsiCode["no bold"] " │\n" \
            "│ " Locale["et"]["name"] "            - " AnsiCode["bold"] "et" AnsiCode["no bold"] "    │ " Locale["lv"]["name"] "        - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["name"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] " │\n" \
            "│ " Locale["tl"]["name"] "            - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │ " Locale["lt"]["name"] "     - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["ur"]["name"] "       - " AnsiCode["bold"] "ur" AnsiCode["no bold"] " │\n" \
            "│ " Locale["fi"]["name"] "             - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "    │ " Locale["mk"]["name"] "     - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["name"] " - " AnsiCode["bold"] "vi" AnsiCode["no bold"] " │\n" \
            "│ " Locale["fr"]["name"] "              - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "    │ " Locale["ms"]["name"] "          - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["cy"]["name"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] " │\n" \
            "│ " Locale["gl"]["name"] "            - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "    │ " Locale["mt"]["name"] "        - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["yi"]["name"] "    - " AnsiCode["bold"] "yi" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ka"]["name"] "            - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "    │ " Locale["mi"]["name"] "          - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["yo"]["name"] "     - " AnsiCode["bold"] "yo" AnsiCode["no bold"] " │\n" \
            "│ " Locale["de"]["name"] "              - " AnsiCode["bold"] "de" AnsiCode["no bold"] "    │ " Locale["mr"]["name"] "        - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["zu"]["name"] "       - " AnsiCode["bold"] "zu" AnsiCode["no bold"] " │\n" \
            "└─────────────────────────────┴──────────────────────┴─────────────────┘"
    else
        return "┌────────────────────┬────────────────────────┬─────────────────────┐\n" \
            "│ " Locale["af"]["display"] "    - " AnsiCode["bold"] "af" AnsiCode["no bold"] "  │ " Locale["hi"]["display"] "            - " AnsiCode["bold"] "hi" AnsiCode["no bold"] "  │ " Locale["nl"]["display"] "  - " AnsiCode["bold"] "nl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ar"]["display"] "      - " AnsiCode["bold"] "ar" AnsiCode["no bold"] "  │ " Locale["hmn"]["display"] "            - " AnsiCode["bold"] "hmn" AnsiCode["no bold"] " │ " Locale["no"]["display"] "       - " AnsiCode["bold"] "no" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["az"]["display"] " - " AnsiCode["bold"] "az" AnsiCode["no bold"] "  │ " Locale["hr"]["display"] "         - " AnsiCode["bold"] "hr" AnsiCode["no bold"] "  │ " Locale["pa"]["display"] "       - " AnsiCode["bold"] "pa" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["be"]["display"] "   - " AnsiCode["bold"] "be" AnsiCode["no bold"] "  │ " Locale["ht"]["display"] "   - " AnsiCode["bold"] "ht" AnsiCode["no bold"] "  │ " Locale["pl"]["display"] "      - " AnsiCode["bold"] "pl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bg"]["display"] "    - " AnsiCode["bold"] "bg" AnsiCode["no bold"] "  │ " Locale["hu"]["display"] "           - " AnsiCode["bold"] "hu" AnsiCode["no bold"] "  │ " Locale["pt"]["display"] "   - " AnsiCode["bold"] "pt" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bn"]["display"] "        - " AnsiCode["bold"] "bn" AnsiCode["no bold"] "  │ " Locale["hy"]["display"] "          - " AnsiCode["bold"] "hy" AnsiCode["no bold"] "  │ " Locale["ro"]["display"] "      - " AnsiCode["bold"] "ro" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["bs"]["display"] "     - " AnsiCode["bold"] "bs" AnsiCode["no bold"] "  │ " Locale["id"]["display"] " - " AnsiCode["bold"] "id" AnsiCode["no bold"] "  │ " Locale["ru"]["display"] "     - " AnsiCode["bold"] "ru" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ca"]["display"] "       - " AnsiCode["bold"] "ca" AnsiCode["no bold"] "  │ " Locale["ig"]["display"] "             - " AnsiCode["bold"] "ig" AnsiCode["no bold"] "  │ " Locale["sk"]["display"] "  - " AnsiCode["bold"] "sk" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ceb"]["display"] "      - " AnsiCode["bold"] "ceb" AnsiCode["no bold"] " │ " Locale["is"]["display"] "         - " AnsiCode["bold"] "is" AnsiCode["no bold"] "  │ " Locale["sl"]["display"] " - " AnsiCode["bold"] "sl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["cs"]["display"] "      - " AnsiCode["bold"] "cs" AnsiCode["no bold"] "  │ " Locale["it"]["display"] "         - " AnsiCode["bold"] "it" AnsiCode["no bold"] "  │ " Locale["so"]["display"] "    - " AnsiCode["bold"] "so" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["cy"]["display"] "      - " AnsiCode["bold"] "cy" AnsiCode["no bold"] "  │ " Locale["ja"]["display"] "           - " AnsiCode["bold"] "ja" AnsiCode["no bold"] "  │ " Locale["sq"]["display"] "       - " AnsiCode["bold"] "sq" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["da"]["display"] "        - " AnsiCode["bold"] "da" AnsiCode["no bold"] "  │ " Locale["jv"]["display"] "        - " AnsiCode["bold"] "jv" AnsiCode["no bold"] "  │ " Locale["sr"]["display"] "      - " AnsiCode["bold"] "sr" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["de"]["display"] "      - " AnsiCode["bold"] "de" AnsiCode["no bold"] "  │ " Locale["ka"]["display"] "          - " AnsiCode["bold"] "ka" AnsiCode["no bold"] "  │ " Locale["sv"]["display"] "     - " AnsiCode["bold"] "sv" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["el"]["display"] "     - " AnsiCode["bold"] "el" AnsiCode["no bold"] "  │ " Locale["km"]["display"] "         - " AnsiCode["bold"] "km" AnsiCode["no bold"] "  │ " Locale["sw"]["display"] "   - " AnsiCode["bold"] "sw" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["en"]["display"] "      - " AnsiCode["bold"] "en" AnsiCode["no bold"] "  │ " Locale["kn"]["display"] "             - " AnsiCode["bold"] "kn" AnsiCode["no bold"] "  │ " Locale["ta"]["display"] "        - " AnsiCode["bold"] "ta" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["eo"]["display"] "    - " AnsiCode["bold"] "eo" AnsiCode["no bold"] "  │ " Locale["ko"]["display"] "           - " AnsiCode["bold"] "ko" AnsiCode["no bold"] "  │ " Locale["te"]["display"] "       - " AnsiCode["bold"] "te" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["es"]["display"] "      - " AnsiCode["bold"] "es" AnsiCode["no bold"] "  │ " Locale["la"]["display"] "           - " AnsiCode["bold"] "la" AnsiCode["no bold"] "  │ " Locale["th"]["display"] "         - " AnsiCode["bold"] "th" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["et"]["display"] "        - " AnsiCode["bold"] "et" AnsiCode["no bold"] "  │ " Locale["lo"]["display"] "              - " AnsiCode["bold"] "lo" AnsiCode["no bold"] "  │ " Locale["tl"]["display"] "     - " AnsiCode["bold"] "tl" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["eu"]["display"] "      - " AnsiCode["bold"] "eu" AnsiCode["no bold"] "  │ " Locale["lt"]["display"] "         - " AnsiCode["bold"] "lt" AnsiCode["no bold"] "  │ " Locale["tr"]["display"] "      - " AnsiCode["bold"] "tr" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fa"]["display"] "        - " AnsiCode["bold"] "fa" AnsiCode["no bold"] "  │ " Locale["lv"]["display"] "         - " AnsiCode["bold"] "lv" AnsiCode["no bold"] "  │ " Locale["uk"]["display"] "  - " AnsiCode["bold"] "uk" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fi"]["display"] "        - " AnsiCode["bold"] "fi" AnsiCode["no bold"] "  │ " Locale["mi"]["display"] "            - " AnsiCode["bold"] "mi" AnsiCode["no bold"] "  │ " Locale["ur"]["display"] "        - " AnsiCode["bold"] "ur" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["fr"]["display"] "     - " AnsiCode["bold"] "fr" AnsiCode["no bold"] "  │ " Locale["mk"]["display"] "       - " AnsiCode["bold"] "mk" AnsiCode["no bold"] "  │ " Locale["vi"]["display"] "  - " AnsiCode["bold"] "vi" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["ga"]["display"] "      - " AnsiCode["bold"] "ga" AnsiCode["no bold"] "  │ " Locale["mn"]["display"] "           - " AnsiCode["bold"] "mn" AnsiCode["no bold"] "  │ " Locale["yi"]["display"] "       - " AnsiCode["bold"] "yi" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["gl"]["display"] "       - " AnsiCode["bold"] "gl" AnsiCode["no bold"] "  │ " Locale["mr"]["display"] "            - " AnsiCode["bold"] "mr" AnsiCode["no bold"] "  │ " Locale["yo"]["display"] "      - " AnsiCode["bold"] "yo" AnsiCode["no bold"] "    │\n" \
            "│ " Locale["gu"]["display"] "       - " AnsiCode["bold"] "gu" AnsiCode["no bold"] "  │ " Locale["ms"]["display"] "    - " AnsiCode["bold"] "ms" AnsiCode["no bold"] "  │ " Locale["zh-CN"]["display"] "    - " AnsiCode["bold"] "zh-CN" AnsiCode["no bold"] " │\n" \
            "│ " Locale["ha"]["display"] "        - " AnsiCode["bold"] "ha" AnsiCode["no bold"] "  │ " Locale["mt"]["display"] "            - " AnsiCode["bold"] "mt" AnsiCode["no bold"] "  │ " Locale["zh-TW"]["display"] "    - " AnsiCode["bold"] "zh-TW" AnsiCode["no bold"] " │\n" \
            "│ " Locale["he"]["display"] "        - " AnsiCode["bold"] "he" AnsiCode["no bold"] "  │ " Locale["ne"]["display"] "            - " AnsiCode["bold"] "ne" AnsiCode["no bold"] "  │ " Locale["zu"]["display"] "     - " AnsiCode["bold"] "zu" AnsiCode["no bold"] "    │\n" \
            "└────────────────────┴────────────────────────┴─────────────────────┘"
}

# Return help message as a string.
function getHelp() {
    return "Usage: translate [options] [source]:[target] [<text>] ...\n" \
        "       translate [options] [source]:[target1]+[target2]+... [<text>] ...\n"
}


var/mapr.awk: END: fix ORS logic (re: 2414bb8f)

# awk script belonging to modernish var/mapr.mm
#
# This converts the input to commands for the shell to 'eval', based
# on parameters inherited from the environment.
#
# --- begin license ---
# Copyright (c) 2018 Martijn Dekker <martijn@inlv.org>, Groningen, Netherlands
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# --- end license ---

function round8(num) {
	return (num % 8 == 0) ? num : (num - num % 8 + 8);
}

# Avoid writing very long physical lines of shell code. Some shells on old systems
# can't deal with physical lines exceeding the minimum guaranteed SIZE_MAX==65535.
function printsh(arg) {
	shlen += length(arg);
	if (shlen >= 65533) {	# SIZE_MAX minus backslash minus linefeed
		print "\\\n";	# line continuation
		shlen = length(arg);
	}
	print arg;
}

BEGIN {
	RS = ENVIRON["_Msh_Mo_d"];

	# Some awk versions need a dummy calculation to convert from string to number.
	opt_s = ENVIRON["_Msh_Mo_s"] + 0;
	opt_n = ENVIRON["_Msh_Mo_n"] + 0;
	opt_c = ENVIRON["_Msh_Mo_c"] + 0;
	opt_m = ENVIRON["_Msh_Mo_m"] + 0;
	arg_max = ENVIRON["_Msh_ARG_MAX"] + 0;

	L_cmd = 0;	# count total length of fixed arguments in command line
	for (i=1; i<ARGC; i++) {
		if (opt_m) {
			L_cmd += length(ARGV[i]) + 1;
		} else {
			# macOS seems to need special argument size aligning to avoid a buffer overflow.
			L_cmd += round8(length(ARGV[i]) + 1) + 8;
		}
	}
	ARGC=1;		# nuke arguments so awk won't take them as input files

	c = 0;		# count number of arguments per command invocation
	L = L_cmd;	# count total argument length per command invocation
	tL = 0;		# count total argument length per batch of commands
	cont = 0;	# flag for continuing with multiple awk invocations

}

NR == 1 {
	NR = ENVIRON["_Msh_M_NR"] + 0;	# number of records: inherit from previous batches

	ORS = "";			# no automatic output record separation
	shlen = 0;			# count length of physical line of shellquoted arguments
	printsh("\"$@\" ");		# print fixed command line argument(s)
}

NR <= opt_s {
	next;
}

opt_n && NR > opt_n + opt_s {
	exit 0;
}

# main:
{
	if (opt_m) {
		L += length($0) + 1;
	} else {
		# macOS seems to need special argument size aligning to avoid a buffer overflow.
		L += round8(length($0) + 1) + 8;
	}

	# Check the counters.
	if ((opt_c && c >= opt_c) || (opt_m ? L >= opt_m : L >= arg_max)) {
		# Try not to process much more than 4 megs of arguments per batch.
		if ((tL += L) >= 4194304) {
			cont = 1;
			exit 0;
		}
		printsh("||_Msh_mapr_ckE \"$@\"||break;\"$@\" ");
		c = 0;
		L = L_cmd;
	}

	c++;

	# Output the record as a shell-quoted argument.
	numsegs = split($0, seg, /'/);
	if (numsegs == 0) {
		printsh("'' ");
	} else {
		for (n = 1; n <= numsegs; n++) {
			printsh( ("'") (seg[n]) (n < numsegs ? "'\\'" : "' ") );
		}
	}
}

END {
	if (NR) {
		printsh("||_Msh_mapr_ckE \"$@\"||break");
		if (cont) {
			print ("\n_Msh_M_NR=") (NR+1) ("\n");
		} else {
			print ("\n_Msh_M_NR=RET0") ("\n");
		}
	}
}

# awk script belonging to modernish var/mapr.mm
#
# This converts the input to commands for the shell to 'eval', based
# on parameters inherited from the environment.
#
# --- begin license ---
# Copyright (c) 2018 Martijn Dekker <martijn@inlv.org>, Groningen, Netherlands
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# --- end license ---

function round8(num) {
	return (num % 8 == 0) ? num : (num - num % 8 + 8);
}

# Avoid writing very long physical lines of shell code. Some shells on old systems
# can't deal with physical lines exceeding the minimum guaranteed SIZE_MAX==65535.
function printsh(arg) {
	shlen += length(arg);
	if (shlen >= 65533) {	# SIZE_MAX minus backslash minus linefeed
		print "\\\n";	# line continuation
		shlen = length(arg);
	}
	print arg;
}

BEGIN {
	RS = ENVIRON["_Msh_Mo_d"];

	# Some awk versions need a dummy calculation to convert from string to number.
	opt_s = ENVIRON["_Msh_Mo_s"] + 0;
	opt_n = ENVIRON["_Msh_Mo_n"] + 0;
	opt_c = ENVIRON["_Msh_Mo_c"] + 0;
	opt_m = ENVIRON["_Msh_Mo_m"] + 0;
	arg_max = ENVIRON["_Msh_ARG_MAX"] + 0;

	L_cmd = 0;	# count total length of fixed arguments in command line
	for (i=1; i<ARGC; i++) {
		if (opt_m) {
			L_cmd += length(ARGV[i]) + 1;
		} else {
			# macOS seems to need special argument size aligning to avoid a buffer overflow.
			L_cmd += round8(length(ARGV[i]) + 1) + 8;
		}
	}
	ARGC=1;		# nuke arguments so awk won't take them as input files

	c = 0;		# count number of arguments per command invocation
	L = L_cmd;	# count total argument length per command invocation
	tL = 0;		# count total argument length per batch of commands
	cont = 0;	# flag for continuing with multiple awk invocations

}

NR == 1 {
	NR = ENVIRON["_Msh_M_NR"] + 0;	# number of records: inherit from previous batches

	ORS = "";			# no automatic output record separation
	shlen = 0;			# count length of physical line of shellquoted arguments
	printsh("\"$@\" ");		# print fixed command line argument(s)
}

NR <= opt_s {
	next;
}

opt_n && NR > opt_n + opt_s {
	exit 0;
}

# main:
{
	if (opt_m) {
		L += length($0) + 1;
	} else {
		# macOS seems to need special argument size aligning to avoid a buffer overflow.
		L += round8(length($0) + 1) + 8;
	}

	# Check the counters.
	if ((opt_c && c >= opt_c) || (opt_m ? L >= opt_m : L >= arg_max)) {
		# Try not to process much more than 4 megs of arguments per batch.
		if ((tL += L) >= 4194304) {
			cont = 1;
			exit 0;
		}
		printsh("||_Msh_mapr_ckE \"$@\"||break;\"$@\" ");
		c = 0;
		L = L_cmd;
	}

	c++;

	# Output the record as a shell-quoted argument.
	numsegs = split($0, seg, /'/);
	if (numsegs == 0) {
		printsh("'' ");
	} else {
		for (n = 1; n <= numsegs; n++) {
			printsh( ("'") (seg[n]) (n < numsegs ? "'\\'" : "' ") );
		}
	}
}

END {
	if (NR) {
		ORS = "\n";
		printsh("||_Msh_mapr_ckE \"$@\"||break");
		if (cont) {
			print ("_Msh_M_NR=") (NR+1);
		} else {
			print "_Msh_M_NR=RET0";
		}
	}
}


Display plurals correctly in testsuite summary

David R Allsopp -- pedantically eschewing lazy plural(s) since 1994.

#########################################################################
#                                                                       #
#                                 OCaml                                 #
#                                                                       #
#         Damien Doligez, projet Gallium, INRIA Rocquencourt            #
#                                                                       #
#   Copyright 2013 Institut National de Recherche en Informatique et    #
#   en Automatique.  All rights reserved.  This file is distributed     #
#   under the terms of the Q Public License version 1.0.                #
#                                                                       #
#########################################################################

function check() {
    if (!in_test){
        printf("error at line %d: found test result without test start\n", NR);
        errored = 1;
    }
}

function clear() {
    curfile = "";
    in_test = 0;
}

function record_pass() {
    check();
    RESULTS[key] = "p";
    delete SKIPPED[curdir];
    clear();
}

function record_skip() {
    check();
    RESULTS[key] = "s";
    clear();
}

# The output cares only if the test passes at least once so if a test passes,
# but then fails in a re-run triggered by a different test, ignore it.
function record_fail() {
    check();
    if (!(key in RESULTS) || RESULTS[key] == "s"){
        RESULTS[key] = "f";
    }
    delete SKIPPED[curdir];
    clear();
}

function record_unexp() {
    if (!(key in RESULTS) || RESULTS[key] == "s"){
        RESULTS[key] = "e";
    }
    delete SKIPPED[curdir];
    clear();
}

/Running tests from '[^']*'/ {
    if (in_test) record_unexp();
    match($0, /Running tests from '[^']*'/);
    curdir = substr($0, RSTART+20, RLENGTH - 21);
    SKIPPED[curdir] = 1;
    key = curdir;
    DIRS[key] = key;
    curfile = "";
}

/ ... testing.* ... testing/ {
    printf("error at line %d: found two test results on the same line\n", NR);
    errored = 1;
}

/^ ... testing '[^']*'/ {
    if (in_test) record_unexp();
    match($0, /... testing '[^']*'/);
    curfile = substr($0, RSTART+13, RLENGTH-14);
    key = sprintf ("%s/%s", curdir, curfile);
    DIRS[key] = curdir;
    in_test = 1;
}

/^ ... testing (with|[^'])/ {
    if (in_test) record_unexp();
    key = curdir;
    DIRS[key] = curdir;
    in_test = 1;
}

/=> passed/ {
    record_pass();
}

/=> skipped/ {
    record_skip();
}

/=> failed/ {
    record_fail();
}

/=> unexpected error/ {
    record_unexp();
}

/^re-ran / {
    if (in_test){
        printf("error at line %d: found re-ran inside a test\n", NR);
        errored = 1;
    }else{
        RERAN[substr($0, 8, length($0)-7)] += 1;
        ++ reran;
    }
}

END {
    if (errored){
        printf ("\n#### Some fatal error occurred during testing.\n\n");
        exit (3);
    }else{
        if (!retries){
            for (key in RESULTS){
                r = RESULTS[key];
                if (r == "p"){
                    ++ passed;
                }else if (r == "f"){
                    ++ failed;
                    fail[failidx++] = key;
                }else if (r == "e"){
                    ++ unexped;
                    unexp[unexpidx++] = key;
                }else if (r == "s"){
                    ++ skipped;
                    curdir = DIRS[key];
                    if (curdir in SKIPPED){
                        if (SKIPPED[curdir]){
                            SKIPPED[curdir] = 0;
                            skips[skipidx++] = curdir;
                        }
                    }else{
                        skips[skipidx++] = key;
                    }
                }
            }
            printf("\n");
            printf("Summary:\n");
            printf("  %3d test%s passed\n", passed, (passed == 1 ? "" : "s"));
            printf("  %3d test%s skipped\n", skipped, (skipped == 1 ? "" : "s"));
            printf("  %3d test%s failed\n", failed, (failed == 1 ? "" : "s"));
            printf("  %3d unexpected error%s\n", unexped, (unexped == 1 ? "" : "s"));
            printf("  %3d tests considered%s\n", length(RESULTS), (length(RESULTS) != passed + skipped + failed + unexped ? " (totals don't add up??)": ""));
            if (reran != 0){
                printf("  %3d test dir re-run%s\n", reran, (reran == 1 ? "" : "s"));
            }
            if (failed != 0){
                printf("\nList of failed tests:\n");
                for (i=0; i < failed; i++) printf("    %s\n", fail[i]);
            }
            if (unexped != 0){
                printf("\nList of unexpected errors:\n");
                for (i=0; i < unexped; i++) printf("    %s\n", unexp[i]);
            }
            if (skipped != 0){
                printf("\nList of skipped tests:\n");
                for (i=0; i < skipidx; i++) printf("    %s\n", skips[i]);
            }
            printf("\n");
            if (failed || unexped){
                printf("#### Something failed. Exiting with error status.\n\n");
                exit 4;
            }
        }else{
            for (key in RESULTS){
                if (RESULTS[key] == "f" || RESULTS[key] == "e"){
                    key = DIRS[key];
                    if (!(key in RERUNS)){
                        RERUNS[key] = 1;
                        if (RERAN[key] < max_retries){
                            printf("%s\n", key);
                        }
                    }
                }
            }
        }
    }
}

#########################################################################
#                                                                       #
#                                 OCaml                                 #
#                                                                       #
#         Damien Doligez, projet Gallium, INRIA Rocquencourt            #
#                                                                       #
#   Copyright 2013 Institut National de Recherche en Informatique et    #
#   en Automatique.  All rights reserved.  This file is distributed     #
#   under the terms of the Q Public License version 1.0.                #
#                                                                       #
#########################################################################

function check() {
    if (!in_test){
        printf("error at line %d: found test result without test start\n", NR);
        errored = 1;
    }
}

function clear() {
    curfile = "";
    in_test = 0;
}

function record_pass() {
    check();
    RESULTS[key] = "p";
    delete SKIPPED[curdir];
    clear();
}

function record_skip() {
    check();
    RESULTS[key] = "s";
    clear();
}

# The output cares only if the test passes at least once so if a test passes,
# but then fails in a re-run triggered by a different test, ignore it.
function record_fail() {
    check();
    if (!(key in RESULTS) || RESULTS[key] == "s"){
        RESULTS[key] = "f";
    }
    delete SKIPPED[curdir];
    clear();
}

function record_unexp() {
    if (!(key in RESULTS) || RESULTS[key] == "s"){
        RESULTS[key] = "e";
    }
    delete SKIPPED[curdir];
    clear();
}

/Running tests from '[^']*'/ {
    if (in_test) record_unexp();
    match($0, /Running tests from '[^']*'/);
    curdir = substr($0, RSTART+20, RLENGTH - 21);
    SKIPPED[curdir] = 1;
    key = curdir;
    DIRS[key] = key;
    curfile = "";
}

/ ... testing.* ... testing/ {
    printf("error at line %d: found two test results on the same line\n", NR);
    errored = 1;
}

/^ ... testing '[^']*'/ {
    if (in_test) record_unexp();
    match($0, /... testing '[^']*'/);
    curfile = substr($0, RSTART+13, RLENGTH-14);
    key = sprintf ("%s/%s", curdir, curfile);
    DIRS[key] = curdir;
    in_test = 1;
}

/^ ... testing (with|[^'])/ {
    if (in_test) record_unexp();
    key = curdir;
    DIRS[key] = curdir;
    in_test = 1;
}

/=> passed/ {
    record_pass();
}

/=> skipped/ {
    record_skip();
}

/=> failed/ {
    record_fail();
}

/=> unexpected error/ {
    record_unexp();
}

/^re-ran / {
    if (in_test){
        printf("error at line %d: found re-ran inside a test\n", NR);
        errored = 1;
    }else{
        RERAN[substr($0, 8, length($0)-7)] += 1;
        ++ reran;
    }
}

END {
    if (errored){
        printf ("\n#### Some fatal error occurred during testing.\n\n");
        exit (3);
    }else{
        if (!retries){
            for (key in RESULTS){
                r = RESULTS[key];
                if (r == "p"){
                    ++ passed;
                }else if (r == "f"){
                    ++ failed;
                    fail[failidx++] = key;
                }else if (r == "e"){
                    ++ unexped;
                    unexp[unexpidx++] = key;
                }else if (r == "s"){
                    ++ skipped;
                    curdir = DIRS[key];
                    if (curdir in SKIPPED){
                        if (SKIPPED[curdir]){
                            SKIPPED[curdir] = 0;
                            skips[skipidx++] = curdir;
                        }
                    }else{
                        skips[skipidx++] = key;
                    }
                }
            }
            printf("\n");
            printf("Summary:\n");
            printf("  %3d test(s) passed\n", passed);
            printf("  %3d test(s) skipped\n", skipped);
            printf("  %3d test(s) failed\n", failed);
            printf("  %3d unexpected error(s)\n", unexped);
            printf("  %3d tests considered%s\n", length(RESULTS), (length(RESULTS) != passed + skipped + failed + unexped ? " (totals don't add up??)": ""));
            if (reran != 0){
                printf("  %3d test dir re-run(s)\n", reran);
            }
            if (failed != 0){
                printf("\nList of failed tests:\n");
                for (i=0; i < failed; i++) printf("    %s\n", fail[i]);
            }
            if (unexped != 0){
                printf("\nList of unexpected errors:\n");
                for (i=0; i < unexped; i++) printf("    %s\n", unexp[i]);
            }
            if (skipped != 0){
                printf("\nList of skipped tests:\n");
                for (i=0; i < skipidx; i++) printf("    %s\n", skips[i]);
            }
            printf("\n");
            if (failed || unexped){
                printf("#### Some tests failed. Exiting with error status.\n\n");
                exit 4;
            }
        }else{
            for (key in RESULTS){
                if (RESULTS[key] == "f" || RESULTS[key] == "e"){
                    key = DIRS[key];
                    if (!(key in RERUNS)){
                        RERUNS[key] = 1;
                        if (RERAN[key] < max_retries){
                            printf("%s\n", key);
                        }
                    }
                }
            }
        }
    }
}


r9836/sofa-dev : FIX: trying to better flag files that are in SOFA_DEV but commented in the .pro

#!/usr/bin/awk -f
# This script removes parts flagged by SOFA_DEV inside qmake project files
# The file with the relevant parts removed is output to the standard output,
# while files mentionned inside removed parts are output to the standard error.
# This can be used to remove then from the repository by svn rm'ing them.

# If you never used awk, a good introduction is available at http://www.cs.hmc.edu/qref/awk.html

# init
BEGIN {
    infilelist=0;
    blk_before=0;
    blk_after=0;
    blk_dev=0;
}

{ blk_before=blk_after; }

/[{}]/ {
  split($0,a,"#")
  if (a[1]!="") {
    split(a[1],beg,"{")
    split(a[1],end,"}")
    blk_after = blk_before + length(beg) - length(end)
  }
}

END {
    if (blk_after != 0) print "# ERROR: unmatched brackets"
}

# Match blocks conditionnally included depending on the SOFA_DEV flag
# Note that we now count the brackets in the source file to find the
# SOFA_DEV closing one instead of relying on the presence of a comment

blk_dev==0 && /contains[ \t]*\([ \t]*DEFINES[ \t]*,[ \t]*SOFA_DEV[ \t]*\)[ \t]*{/ {
    blk_dev=blk_after;
    infilelist=0;
}

blk_dev>0 && blk_after < blk_dev {
    blk_dev=0;
    next;
}

# /contains[ \t]*\([ \t]*DEFINES[ \t]*,[ \t]*SOFA_DEV[ \t]*\)[ \t]*{/,/[ \t]*}.*SOFA_DEV/ {
blk_dev>0 {
    #print "# " $0
    # look for a filename
    # we assume files and directories are listed inside variables containing SUBDIRS, SOURCES or HEADERS
    f0=1;
    nf=NF;
    if ($nf~/\r/) {
      #print "#CR <" $nf ">"
      gsub(/[\r\n]/,"",$nf);
      #print "#CRF <" $nf ">"
      if ($nf=="") nf--;
    }
    if (infilelist==0) {
	if (($1~"SUBDIRS" || $1~"SOURCES" || $1~"HEADERS") && ($2=="=" || $2=="+=")) {
	    #print "#infilelist " $1
	    infilelist=1;
	    f0=3; # first file is in 3rd field
	}
	else if ($1~"###") {
	    #print "#infilelist " $1
	    infilelist=1;
	    f0=2; # first file is in 3rd field
	}
    }
    if (infilelist) {
	for(f=f0;f<=nf && !(f==nf && $f~/^[:space:]*\\[:space:]*$/);f++) {
	    fname=$f
	    gsub(/[\r\n]/,"",fname);
	    gsub(/\\[:space:]*$/,"",fname);
	    gsub(/^##*/,"",fname);
	    if (fname != "") print fname > "/dev/stderr";
	}
	if (f>nf && (nf==0 || $nf!~/\\[:space:]*$/)) { # no "\\" is put at the end of the line -> end of list
	    #print "#end"
	    infilelist=0;
	}
    }
    next;
}

# Match lines mentionning SOFA_DEV, such as the point where it is defined
/SOFA_DEV/ { next; }

# other: simply print the line
#{ print blk_before "<" $0 ">" blk_after; }
{ print }

#!/usr/bin/awk -f
# This script removes parts flagged by SOFA_DEV inside qmake project files
# The file with the relevant parts removed is output to the standard output,
# while files mentionned inside removed parts are output to the standard error.
# This can be used to remove then from the repository by svn rm'ing them.

# If you never used awk, a good introduction is available at http://www.cs.hmc.edu/qref/awk.html

# init
BEGIN {
    infilelist=0;
    blk_before=0;
    blk_after=0;
    blk_dev=0;
}

{ blk_before=blk_after; }

/[{}]/ {
  split($0,a,"#")
  if (a[1]!="") {
    split(a[1],beg,"{")
    split(a[1],end,"}")
    blk_after = blk_before + length(beg) - length(end)
  }
}

END {
    if (blk_after != 0) print "# ERROR: unmatched brackets"
}

# Match blocks conditionnally included depending on the SOFA_DEV flag
# Note that we now count the brackets in the source file to find the
# SOFA_DEV closing one instead of relying on the presence of a comment

blk_dev==0 && /contains[ \t]*\([ \t]*DEFINES[ \t]*,[ \t]*SOFA_DEV[ \t]*\)[ \t]*{/ {
    blk_dev=blk_after;
    infilelist=0;
}

blk_dev>0 && blk_after < blk_dev {
    blk_dev=0;
    next;
}

# /contains[ \t]*\([ \t]*DEFINES[ \t]*,[ \t]*SOFA_DEV[ \t]*\)[ \t]*{/,/[ \t]*}.*SOFA_DEV/ {
blk_dev>0 {
    #print "# " $0
    # look for a filename
    # we assume files and directories are listed inside variables containing SUBDIRS, SOURCES or HEADERS
    f0=1;
    nf=NF;
    if ($nf~/\r/) {
      #print "#CR <" $nf ">"
      gsub(/[\r\n]/,"",$nf);
      #print "#CRF <" $nf ">"
      if ($nf=="") nf--;
    }
    if (infilelist==0) {
	if (($1~"SUBDIRS" || $1~"SOURCES" || $1~"HEADERS") && ($2=="=" || $2=="+=")) {
	    #print "#infilelist " $1
	    infilelist=1;
	    f0=3; # first file is in 3rd field
	}
    }
    if (infilelist) {
	for(f=f0;f<=nf && !(f==nf && $f~/^[:space:]*\\[:space:]*$/);f++) {
	    fname=$f
	    gsub(/[\r\n]/,"",fname);
	    gsub(/\\[:space:]*$/,"",fname);
	    if (fname != "#") print fname > "/dev/stderr";
	}
	if (f>nf && (nf==0 || $nf!~/\\[:space:]*$/)) { # no "\\" is put at the end of the line -> end of list
	    #print "#end"
	    infilelist=0;
	}
    }
    next;
}

# Match lines mentionning SOFA_DEV, such as the point where it is defined
/SOFA_DEV/ { next; }

# other: simply print the line
#{ print blk_before "<" $0 ">" blk_after; }
{ print }


Fix some special cases

Fix some special cases

-c-, Brotherhood of Blood Murder

# Produce a raw data spreadsheet from URLs found in https://watch.mhzchoice.com/sitemap.xml

# INVOCATION:
#    awk -v ERRORS=$ERRORS -v RAW_CREDITS=$RAW_CREDITS -v RAW_TITLES=$RAW_TITLES \
#        -f getMHzFromSitemap.awk >>$UNSORTED

# Field numbers
# 1 Title  2 Seasons  3 Episodes  4 Duration  5 Genre  6 Country  7 Language  8 Rating  9 Description

### Begin season processing

# Determine whether this is a page 2
#    <meta name="apple-itunes-app" content="app-id=1096194231, \
#        app-argument=https://mhzchoice.vhx.tv/detective-montalbano?page=2">
/<meta name="apple-itunes-app" content=".*?page=2">/ {
    page2 = "yes"
    next
}

# Season Title & Season URL
#    <form class="form"><input value="https://watch.mhzchoice.com/gasmamman/season:1" type="text" \
#        class="text text-center border-none site-background-color site-font-secondary-color" /></form>
# This returns incorrect values if page2 == "yes", but those values are never used
/<form class="form">/ {
    split ($0,fld,"\"")
    seasonURL = fld[4]
    shortSeasonURL = seasonURL
    sub (/.*watch/,"watch",shortSeasonURL)
    split (seasonURL,fld,":")
    seasonNumber = fld[3]
    seasonTitle = "Season " seasonNumber
    # print "==> seasonURL = " seasonURL > "/dev/stderr"
    # print "==> seasonNumber = " seasonNumber > "/dev/stderr"
    # print "==> seasonTitle = " seasonTitle > "/dev/stderr"
    next
}

# Season episodes
#

#      9 Episodes
#

# Extract only the number of episodes, # but if this is page 2 skip to avoid double counting
/<h2 class=.*content-label/,/<\/h2>/ {
    sub (/^ */,"")
    if ($0 ~ / Episode/) {
        seasonEpisodes = $1
        next
    }
}

### Begin show processing

# Show Title
#    <title>Gasmamman - MHz Choice</title>
/<title>/ {
    split ($0,fld,"[<>]")
    showTitle = fld[3]
    sub (/ - MHz Choice/,"",showTitle)
    gsub (/'/,"'",showTitle)
    print showTitle >> RAW_TITLES
    # print "==> showTitle = " showTitle > "/dev/stderr"
    next
}

# Show Descriptor
#    <meta name="description" content="DRAMA - CRIME | SWEDEN | SWEDISH WITH ENGLISH SUBTITLES | TV-14
#    Alexandra Rapaport stars as a suburban mom pulled into the criminal \
#        underworld to pay off her murdered husband’s debts.">
#
# There should be four header fields prior to the description
/<meta name="description" content="/,/">/ {
     # if we're on the first line of this block ...
    if ($0 ~ /name="description" content="/) {
        headerAdded = "no"
        sub (/.*name="description" content="/,"")
    }
    # If we find a header, clean it up and put it before the description
    if ($0 ~ /\|[ ]+TV-/) {
        sub (/WITH ENGLISH SUBTITLES /,"")
        sub (/SCANDINAVIAN CRIME FICTION/,"Sweden")
        sub (/NONFICTION - DOCUMENTARY/,"Documentary")
        sub (/NON-FICTION - DOCUMENTARY/,"Documentary")
        gsub (/ \|[ ]+/,"|")
        sub (/\r/,"")
        # Split out header fields
        numFields = split ($0,fld,"\|")
        # lowercase everything but the first character in all fields but the last
        for (i = 1; i < numFields; ++i) {
            fld[i] = substr(fld[i],1,1) tolower(substr(fld[i],2))
            # uppercase the first character of any second word
            if (match (fld[i],/ /)) {
                fld[i] = substr(fld[i],1,RSTART) toupper(substr(fld[i],RSTART+1,1)) (substr(fld[i],RSTART+2))
            }
        }
        # Put the finalized header before the description
        if (numFields > 3 ) {
            sub (/Drama-crime/,"Drama - crime",fld[1])
            gsub (/ /,"",fld[4])
            showDescriptor =  fld[1] "\t" fld[2] "\t" fld[(numFields-1)] "\t" fld[(numFields)] "\t"
            headerAdded = "yes"
        }
    } else {
        # if we didn't find a header in this block, add a blank one
        if (headerAdded == "no") {
            printf ("==> Added blank header for \"%s\"\n", showTitle) >> ERRORS
            showDescriptor = "\t\t\t\t"
        }
        # We found a description, clean it up and add it
        gsub (/  */," ")
        gsub (/'/,"'")
        gsub (/"/,"\"")
        gsub (/&/,"\\&")
        gsub (/‘/,"’")
        gsub (/’/,"’")
        gsub (/“/,"“")
        gsub (/”/,"”")
        gsub (/\r/," ")
        # if it's not the last line of the description, add it
        if ($0 !~ /"\>/) {
            printf ("==> Multi line description in \"%s\"\n", showTitle) >> ERRORS
            showDescriptor = showDescriptor $0
        } else {
            # if it's the last line of the description, add it
            sub (/"\>/,"")
            showDescriptor = showDescriptor $0
        }
    }
    # print "==> showDescriptor = " showDescriptor > "/dev/stderr"
    next
}

# Show URL
#    <meta property="og:url" content="https://watch.mhzchoice.com/gasmamman">
/<meta property="og:url" content=/ {
    split ($0,fld,"\"")
    showURL = fld[4]
    # print "==> showURL = " showURL > "/dev/stderr"
    next
}

# Show seasons
#

#        3 Seasons
#

# Extract only the number of seasons, # but if this is page 2 skip to avoid double counting
/<h2 class=.*collection-stats"/,/<\/h2>/ {
    sub (/^ */,"")
    # Only if there are two or more seasons, a show with only one season doesn't have this
    if ($0 ~ / Season/) {
        showSeasons = $1
        next
    }
}

### Begin episode processing

# Episode URL(s) and -c-x Episode Number
#

#
/
/,/<a href="https:/ {
    if ($0 ~ / episodeURL = " episodeURL > "/dev/stderr"
        if (match (shortEpisodeURL, /-c-x[[:digit:]]{3,4}$/)) {
            cxEpisodeNumber = substr(shortEpisodeURL, RSTART+RLENGTH-2, 2)
            # print shortEpisodeURL " cx " cxEpisodeNumber >"/dev/stderr"
        }
        next
    }
}

# Episode Duration(s)
# Used to be on one line
#
44:15

#
# Now it's on six
#

#      47:58
#

# Extract the duration
/<div class="duration-container/,/<\/div>/ {
    gsub (/ /,"")
    if ($0 ~ /[[:digit:]]+:[[:digit:]]+/)
        episodeDuration = $0
    # Spreadsheets decipher 2 part durations as time-of-day so make sure they're 3 parts
    if (split (episodeDuration, tm, ":") == 2)
        episodeDuration = "00:" episodeDuration
    if ($0 ~ /<\/div>/) {
        # print "==> episodeDuration = " episodeDuration > "/dev/stderr"
        next
    }
}

# Episode Title(s)
#
 \
#        Gåsmamman: Episode 01 (Sn 1 Ep 1)

/<h3 class="tooltip-item-title/{
    split ($0,fld,"[<>]")
    episodeTitle = fld[5]
    gsub (/'/,"'",episodeTitle)
    gsub (/"/,"\"\"",episodeTitle)
    gsub (/&/,"\\&",episodeTitle)
    sub (/^[[:space:]]/,"",episodeTitle)
    sub (/[[:space:]]+$/,"",episodeTitle)
    #
    # Episode Types(s)
    # Default episodeType to "E"
    episodeType = "E"
    # If episode is a BONUS:, set episodeType to "X"
    if (episodeTitle ~ /BONUS|Montalbano and Me/) {
        episodeType = "X"
    }
    # If episode is a Trailer (i.e. First look), set episodeType to "T"
    if (episodeTitle ~ /^PR \|/) {
        seasonEpisodes = seasonEpisodes - 1
        episodeType = "T"
        prEpisodeNumber += 1
        # print shortEpisodeURL " pr " prEpisodeNumber >"/dev/stderr"
    }
    # If episode is a upcoming, i.e. - EP 507" Available... use its episode number
        if (match (episodeTitle, /-[[:space:]]{1,2}EP [[:digit:]]{3,4}/)) {
            snEpisodeNumber = substr(episodeTitle, RSTART+RLENGTH-2, 2)
        # print shortEpisodeURL " pr " prEpisodeNumber >"/dev/stderr"
    }
    # print "==> episodeType = " episodeType > "/dev/stderr"
    #
    # Season and episode numbers
    #
    # Special case episode numbers
    # Montalbano episodes have no season, make them season 1
    if (episodeTitle ~ /^Montalbano|^Detective Montalbano:/) {
        sub (/\(Ep/,"(Sn 1 Ep",episodeTitle)
        sub (/^Montalbano:/,"Detective Montalbano:",episodeTitle)
        sub (/^Montalbano and Me/,"Detective Montalbano: Montalbano and Me",episodeTitle)
    }
    # Baantjer Sn 1 Ep 12 is missing a parens
    sub (/Brotherhood of Blood Murder Sn/, "Brotherhood of Blood Murder (Sn",episodeTitle)
    # A Night in ... is missing episode numbers
    if (shortEpisodeURL ~ /season:1\/videos\/a-night-in/)
        snEpisodeNumber = 1

    # Grab the Episode Number from the trailing (Sn 1 Ep 1)
    # Episode Number(s)
    if (match (episodeTitle,/\(.*[Ee][Pp][ ]*[[:digit:]]+[[:space:]]*\)/)) {
        # print "==> showTitle = " showTitle > "/dev/stderr"
        snEpisodeNumber = substr(episodeTitle, RSTART, RLENGTH)
        sub (/.*[[:space:]]/,"",snEpisodeNumber)
        sub (/\).*/,"",snEpisodeNumber)
        # print shortEpisodeURL " sn " snEpisodeNumber >"/dev/stderr"
    }

    # Octopus and some others uses -c-0
    if (match (shortEpisodeURL, /-c-[[:digit:]]{5}/)) {
        if (snEpisodeNumber == "" && prEpisodeNumber == "") {
            cxEpisodeNumber = substr(shortEpisodeURL, RSTART+RLENGTH-3, 3)
            # print shortEpisodeURL " c- " snEpisodeNumber >"/dev/stderr"
         }
    }

    # print "==> episodeTitle = " episodeTitle > "/dev/stderr"
    # Handle normal (Sn 1 Ep 1) with variations in spacing and capitalization
    # and ones missing the second letter (Sn 1 E 1), (S1 E1), or wrong second letter (Sm 1 Ep 1)
    if (match (episodeTitle,\
        /[Ss][Nnm]*[ ]*[[:digit:]]+[ ]+[Ee][Pp]*[ ]*[[:digit:]]+[[:space:]]*\)/))  {
            if (episodeTitle !~ / \(Sn [[:digit:]]+ Ep [[:digit:]]+\)/)
                printf ("==> Malformed Sn/Ep in \"%s: %s\"\n", showTitle, episodeTitle) >> ERRORS
            sub (/[ ]*\(S[Nnm]*[ ]*[[:digit:]]+[ ]+[Ee][Pp]*[ ]*[[:digit:]]+[[:space:]]*\)/,\
                "",episodeTitle)
            # print "==> episodeTitle = " episodeTitle > "/dev/stderr"
    }
    next
}

### Wrap-up episode processing when Episode Description is found
### print only on LONG_SPREADSHEET
/
<span class='media-identifier/,/<\/div>/ {
    sub (/^ */,"")
    # print $0 > "/dev/stderr"

    # Episode Description(s)
    #

    #
Preparing for her sister's wedding, Sonja's idyllic life is shattered by tragedy.
    #

    if ($0 ~ /
/) {
        split ($0,fld,"[<>]")
        paragraph = fld[3]
        gsub (/&/,"\\&",paragraph)
        # Could be in multiple paragraphs
        descriptionLinesFound += 1
        if (paragraph != "")
            episodeDescription = episodeDescription (descriptionLinesFound == 1 ? "" : " ") paragraph
        gsub (/&/,"\\&",episodeDescription)
        gsub (/'/,"'",episodeDescription)
        # print "descriptionLinesFound = " descriptionLinesFound > "/dev/stderr"
        # print "==> episodeDescription from
 = \n" episodeDescription > "/dev/stderr"
        next
    }
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman/season:1/videos/gasmamman-episode-01-sn-1-ep-1-1";\
    #  "Gasmamman, S01E01, Gåsmamman: Episode 01 (Sn 1 Ep 1)")
    if ($0 ~ /<\/div>/) {
        # Make sure episodeDescription is valid
        if (episodeDescription == "") {
            if (episodeType == "T") {
                episodeDescription = episodeTitle
                # print "==> episodeDescription from title = " episodeDescription > "/dev/stderr"
            } else {
                print "==> No description: " shortEpisodeURL >> ERRORS
            }
        }
        if (episodeDescription ~ /^PR \|/)
            sub (/^PR \| /,"",episodeDescription)
        # print "==> episodeDescription = \n" episodeDescription > "/dev/stderr"
        #
        # Check for valid seasonNumber and episodeNumber before using them
        if (seasonNumber == "")
            printf ("==> Missing seasonNumber in \"%s: %s\" %s\n", showTitle,
                    episodeTitle, shortEpisodeURL) >> ERRORS
        #
        episodeNumber = snEpisodeNumber
        if (cxEpisodeNumber != "")
            episodeNumber = cxEpisodeNumber
        if (prEpisodeNumber != "" && cxEpisodeNumber == "")
            episodeNumber = prEpisodeNumber
        #
        if (episodeNumber == "")
            printf ("==> Missing episodeNumber in \"%s: %s\" %s\n", showTitle,
                    episodeTitle, shortEpisodeURL) >> ERRORS
        #
        episodeLink = sprintf ("=HYPERLINK(\"%s\";\"%s, S%02d%s%02d, %s\")", episodeURL, showTitle,
                    seasonNumber, episodeType, episodeNumber, episodeTitle)
        #
        # Make sure episodeDuration is valid
        if (split (episodeDuration, tm, ":") == 3) {
            # Canonicalize episodeDuration to 3 parts like other services
            episodeDuration = sprintf ("%02d:%02d:%02d",tm[1],tm[2],tm[3])
        } else {
            printf ("==> Bad episodeDuration %s in \"%s: %s\"\n", episodeDuration, showTitle,
                    episodeTitle) >> ERRORS
            episodeDuration = ""
        }
        #
        # Print "episode" line
        printf ("%s\t\t\t%s\t\t\t\t\t%s\n", episodeLink, episodeDuration, episodeDescription)
        #
        # Look for directors
        director_name = episodeDescription
        # Skip UTF-8 for now...
        # if (gsub (/\xc2\xa0/," ",director_name)) {
            # printf ("==> UTF-8 non-breaking-space in %s, S%02d%s%02d, %s\n", showTitle, seasonNumber,
                    # episodeType, episodeNumber, episodeTitle) >> ERRORS
            # print "    " episodeDescription >> ERRORS
        # }
        if (director_name ~ /[Dd]irected by /) {
            sub (/.*[Dd]irected by /,"",director_name)
            sub (/,.*$/,"",director_name)
            sub (/ [0-9][0-9][0-9][0-9]\./,"",director_name)
            sub (/[[:space:]]+$/,"",director_name)
            sub (/\.$/,"",director_name)
            # Special case director names
            if (director_name ~ /Manetti Bros/)
                director_name = "The Manetti Bros."
            if (director_name ~ /Andrea and Antonio Frazzi/)
                director_name = "Andrea Frazzi and Antonio Frazzi"
            #
            if (match (director_name, " and ") || match (director_name, " & ")) {
                dname = substr(director_name,1,RSTART-1)
                director_name = substr(director_name,RSTART+RLENGTH)
                printf ("%s\tdirector\ttv_show\t%s\n", dname, showTitle) >> RAW_CREDITS
            }
            printf ("%s\tdirector\ttv_show\t%s\n", director_name, showTitle) >> RAW_CREDITS
        }
        # Make sure there is no carryover
        descriptionLinesFound = 0
        episodeLink = ""
        episodeURL =""
        shortEpisodeURL = ""
        episodeType = ""
        episodeNumber = ""
        cxEpisodeNumber = ""
        snEpisodeNumber = ""
        episodeTitle = ""
        episodeDuration = ""
        episodeDescription =""
    }
}

### Wrap-up show processing - print on standard out

# Footer at end of file
#
/ "/dev/stderr"
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman";"Gasmamman")
    showLink = "=HYPERLINK(\"" showURL "\";\"" showTitle "\")"
    #
    # Shows with only one season have a blank showSeasons
    if (showSeasons == "")
        showSeasons = 1
    # in most cases, showSeasons = the final season number, i.e.
    # a show with two seasons would have seasons 1 and 2
    finalSeason = showSeasons
    # Special case discontinuous seasons, e.g. 2 seasons, but numbered 1 and 3
    if (showURL ~ /\/wallander$/)
        finalSeason = 3
    #
    # Wrap show, i.e. but only on final season in order to prevent multiples
    # print "==> " showURL " - seasonNumber = " seasonNumber  > "/dev/stderr"
    # print "==> " showTitle " - finalSeason = " finalSeason  > "/dev/stderr"
    if (seasonNumber > finalSeason ) {
        # This should be OK, as printing any single valid season will work - however ...
        printf ("==> Season number %d beyond final season %d: %s\n", seasonNumber, finalSeason,
                shortSeasonURL) >> ERRORS
    }
    if (seasonNumber == finalSeason ) {
        # Print "show" line
        printf ("%s\t%s\t\t\t%s\n", showLink, showSeasons, showDescriptor)
    }
    #
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman/season:1";"Gasmamman, S01, Season 1")
    if (page2 != "yes") {
        seasonLink = sprintf ("=HYPERLINK(\"%s\";\"%s, S%02d, %s\")", seasonURL, showTitle, seasonNumber,
                   seasonTitle)
        # print "==> seasonURL = " seasonURL  > "/dev/stderr"
        # print "==> seasonLink = " seasonLink  > "/dev/stderr"
        # Don't print redundant showDescriptor for season 1
        if (seasonNumber == 1)
            showDescriptor = ""
        # Print "season" line
        printf ("%s\t\t%s\t\t%s\n", seasonLink, seasonEpisodes, showDescriptor)
    }
    #
    # Make sure there is no carryover
    showLink = ""
    showURL = ""
    showTitle = ""
    showSeasons = ""
    showDescriptor = ""
    # print "" > "/dev/stderr"
    #
    page2 = ""
    seasonLink = ""
    seasonURL = ""
    shortSeasonURL = ""
    seasonNumber = ""
    seasonTitle = ""
    seasonEpisodes = ""
}

# Produce a raw data spreadsheet from URLs found in https://watch.mhzchoice.com/sitemap.xml

# INVOCATION:
#    awk -v ERRORS=$ERRORS -v RAW_CREDITS=$RAW_CREDITS -v RAW_TITLES=$RAW_TITLES \
#        -f getMHzFromSitemap.awk >>$UNSORTED

# Field numbers
# 1 Title  2 Seasons  3 Episodes  4 Duration  5 Genre  6 Country  7 Language  8 Rating  9 Description

### Begin season processing

# Determine whether this is a page 2
#    <meta name="apple-itunes-app" content="app-id=1096194231, \
#        app-argument=https://mhzchoice.vhx.tv/detective-montalbano?page=2">
/<meta name="apple-itunes-app" content=".*?page=2">/ {
    page2 = "yes"
    next
}

# Season Title & Season URL
#    <form class="form"><input value="https://watch.mhzchoice.com/gasmamman/season:1" type="text" \
#        class="text text-center border-none site-background-color site-font-secondary-color" /></form>
# This returns incorrect values if page2 == "yes", but those values are never used
/<form class="form">/ {
    split ($0,fld,"\"")
    seasonURL = fld[4]
    shortSeasonURL = seasonURL
    sub (/.*watch/,"watch",shortSeasonURL)
    split (seasonURL,fld,":")
    seasonNumber = fld[3]
    seasonTitle = "Season " seasonNumber
    # print "==> seasonURL = " seasonURL > "/dev/stderr"
    # print "==> seasonNumber = " seasonNumber > "/dev/stderr"
    # print "==> seasonTitle = " seasonTitle > "/dev/stderr"
    next
}

# Season episodes
#

#      9 Episodes
#

# Extract only the number of episodes, # but if this is page 2 skip to avoid double counting
/<h2 class=.*content-label/,/<\/h2>/ {
    sub (/^ */,"")
    if ($0 ~ / Episode/) {
        seasonEpisodes = $1
        next
    }
}

### Begin show processing

# Show Title
#    <title>Gasmamman - MHz Choice</title>
/<title>/ {
    split ($0,fld,"[<>]")
    showTitle = fld[3]
    sub (/ - MHz Choice/,"",showTitle)
    gsub (/'/,"'",showTitle)
    print showTitle >> RAW_TITLES
    # print "==> showTitle = " showTitle > "/dev/stderr"
    next
}

# Show Descriptor
#    <meta name="description" content="DRAMA - CRIME | SWEDEN | SWEDISH WITH ENGLISH SUBTITLES | TV-14
#    Alexandra Rapaport stars as a suburban mom pulled into the criminal \
#        underworld to pay off her murdered husband’s debts.">
#
# There should be four header fields prior to the description
/<meta name="description" content="/,/">/ {
     # if we're on the first line of this block ...
    if ($0 ~ /name="description" content="/) {
        headerAdded = "no"
        sub (/.*name="description" content="/,"")
    }
    # If we find a header, clean it up and put it before the description
    if ($0 ~ /\|[ ]+TV-/) {
        sub (/WITH ENGLISH SUBTITLES /,"")
        sub (/SCANDINAVIAN CRIME FICTION/,"Sweden")
        sub (/NONFICTION - DOCUMENTARY/,"Documentary")
        sub (/NON-FICTION - DOCUMENTARY/,"Documentary")
        gsub (/ \|[ ]+/,"|")
        sub (/\r/,"")
        # Split out header fields
        numFields = split ($0,fld,"\|")
        # lowercase everything but the first character in all fields but the last
        for (i = 1; i < numFields; ++i) {
            fld[i] = substr(fld[i],1,1) tolower(substr(fld[i],2))
            # uppercase the first character of any second word
            if (match (fld[i],/ /)) {
                fld[i] = substr(fld[i],1,RSTART) toupper(substr(fld[i],RSTART+1,1)) (substr(fld[i],RSTART+2))
            }
        }
        # Put the finalized header before the description
        if (numFields > 3 ) {
            sub (/Drama-crime/,"Drama - crime",fld[1])
            gsub (/ /,"",fld[4])
            showDescriptor =  fld[1] "\t" fld[2] "\t" fld[(numFields-1)] "\t" fld[(numFields)] "\t"
            headerAdded = "yes"
        }
    } else {
        # if we didn't find a header in this block, add a blank one
        if (headerAdded == "no") {
            printf ("==> Added blank header for \"%s\"\n", showTitle) >> ERRORS
            showDescriptor = "\t\t\t\t"
        }
        # We found a description, clean it up and add it
        gsub (/  */," ")
        gsub (/'/,"'")
        gsub (/"/,"\"")
        gsub (/&/,"\\&")
        gsub (/‘/,"’")
        gsub (/’/,"’")
        gsub (/“/,"“")
        gsub (/”/,"”")
        gsub (/\r/," ")
        # if it's not the last line of the description, add it
        if ($0 !~ /"\>/) {
            printf ("==> Multi line description in \"%s\"\n", showTitle) >> ERRORS
            showDescriptor = showDescriptor $0
        } else {
            # if it's the last line of the description, add it
            sub (/"\>/,"")
            showDescriptor = showDescriptor $0
        }
    }
    # print "==> showDescriptor = " showDescriptor > "/dev/stderr"
    next
}

# Show URL
#    <meta property="og:url" content="https://watch.mhzchoice.com/gasmamman">
/<meta property="og:url" content=/ {
    split ($0,fld,"\"")
    showURL = fld[4]
    # print "==> showURL = " showURL > "/dev/stderr"
    next
}

# Show seasons
#

#        3 Seasons
#

# Extract only the number of seasons, # but if this is page 2 skip to avoid double counting
/<h2 class=.*collection-stats"/,/<\/h2>/ {
    sub (/^ */,"")
    # Only if there are two or more seasons, a show with only one season doesn't have this
    if ($0 ~ / Season/) {
        showSeasons = $1
        next
    }
}

### Begin episode processing

# Episode URL(s) and -c-x Episode Number
#

#
/
/,/<a href="https:/ {
    if ($0 ~ / episodeURL = " episodeURL > "/dev/stderr"
        if (match (shortEpisodeURL, /-c-x[[:digit:]]{3,4}$/)) {
            cxEpisodeNumber = substr(shortEpisodeURL, RSTART+RLENGTH-2, 2)
            # print shortEpisodeURL " cx " cxEpisodeNumber >"/dev/stderr"
        }
        next
    }
}

# Episode Duration(s)
# Used to be on one line
#
44:15

#
# Now it's on six
#

#      47:58
#

# Extract the duration
/<div class="duration-container/,/<\/div>/ {
    gsub (/ /,"")
    if ($0 ~ /[[:digit:]]+:[[:digit:]]+/)
        episodeDuration = $0
    # Spreadsheets decipher 2 part durations as time-of-day so make sure they're 3 parts
    if (split (episodeDuration, tm, ":") == 2)
        episodeDuration = "00:" episodeDuration
    if ($0 ~ /<\/div>/) {
        # print "==> episodeDuration = " episodeDuration > "/dev/stderr"
        next
    }
}

# Episode Title(s)
#
 \
#        Gåsmamman: Episode 01 (Sn 1 Ep 1)

/<h3 class="tooltip-item-title/{
    split ($0,fld,"[<>]")
    episodeTitle = fld[5]
    gsub (/'/,"'",episodeTitle)
    gsub (/"/,"\"\"",episodeTitle)
    gsub (/&/,"\\&",episodeTitle)
    sub (/^[[:space:]]/,"",episodeTitle)
    sub (/[[:space:]]+$/,"",episodeTitle)
    #
    # Episode Types(s)
    # Default episodeType to "E"
    episodeType = "E"
    # If episode is a BONUS:, set episodeType to "X"
    if (episodeTitle ~ /BONUS|Montalbano and Me/) {
        episodeType = "X"
    }
    # If episode is a Trailer (i.e. First look), set episodeType to "T"
    if (episodeTitle ~ /^PR \|/) {
        seasonEpisodes = seasonEpisodes - 1
        episodeType = "T"
        prEpisodeNumber += 1
        # print shortEpisodeURL " pr " prEpisodeNumber >"/dev/stderr"
    }
    # If episode is a upcoming, i.e. - EP 507" Available... use its episode number
        if (match (episodeTitle, /-[[:space:]]{1,2}EP [[:digit:]]{3,4}\"/)) {
            snEpisodeNumber = substr(episodeTitle, RSTART+RLENGTH-3, 2)
        # print shortEpisodeURL " pr " prEpisodeNumber >"/dev/stderr"
    }
    # print "==> episodeType = " episodeType > "/dev/stderr"
    #
    # Season and episode numbers
    #
    # Special episode number cases...
    # Montalbano episodes have no season, make them season 1
    if (episodeTitle ~ /^Montalbano|^Detective Montalbano:/) {
        sub (/\(Ep/,"(Sn 1 Ep",episodeTitle)
        sub (/^Montalbano:/,"Detective Montalbano:",episodeTitle)
        sub (/^Montalbano and Me/,"Detective Montalbano: Montalbano and Me",episodeTitle)
    }

    # Grab the Episode Number from the trailing (Sn 1 Ep 1)
    # Episode Number(s)
    if (match (episodeTitle,/\(.*[Ee][Pp][ ]*[[:digit:]]+[[:space:]]*\)/)) {
        # print "==> showTitle = " showTitle > "/dev/stderr"
        snEpisodeNumber = substr(episodeTitle, RSTART, RLENGTH)
        sub (/.*[[:space:]]/,"",snEpisodeNumber)
        sub (/\).*/,"",snEpisodeNumber)
        # print shortEpisodeURL " sn " snEpisodeNumber >"/dev/stderr"
    }

    # print "==> episodeTitle = " episodeTitle > "/dev/stderr"
    # Handle normal (Sn 1 Ep 1) with variations in spacing and capitalization
    # and ones missing the second letter (Sn 1 E 1), (S1 E1), or wrong second letter (Sm 1 Ep 1)
    if (match (episodeTitle,\
        /[Ss][Nnm]*[ ]*[[:digit:]]+[ ]+[Ee][Pp]*[ ]*[[:digit:]]+[[:space:]]*\)/))  {
            if (episodeTitle !~ / \(Sn [[:digit:]]+ Ep [[:digit:]]+\)/)
                printf ("==> Malformed Sn/Ep in \"%s: %s\"\n", showTitle, episodeTitle) >> ERRORS
            sub (/[ ]*\(S[Nnm]*[ ]*[[:digit:]]+[ ]+[Ee][Pp]*[ ]*[[:digit:]]+[[:space:]]*\)/,\
                "",episodeTitle)
            # print "==> episodeTitle = " episodeTitle > "/dev/stderr"
    }
    next
}

### Wrap-up episode processing when Episode Description is found
### print only on LONG_SPREADSHEET
/
<span class='media-identifier/,/<\/div>/ {
    sub (/^ */,"")
    # print $0 > "/dev/stderr"

    # Episode Description(s)
    #

    #
Preparing for her sister's wedding, Sonja's idyllic life is shattered by tragedy.
    #

    if ($0 ~ /
/) {
        split ($0,fld,"[<>]")
        paragraph = fld[3]
        gsub (/&/,"\\&",paragraph)
        # Could be in multiple paragraphs
        descriptionLinesFound += 1
        if (paragraph != "")
            episodeDescription = episodeDescription (descriptionLinesFound == 1 ? "" : " ") paragraph
        gsub (/&/,"\\&",episodeDescription)
        gsub (/'/,"'",episodeDescription)
        # print "descriptionLinesFound = " descriptionLinesFound > "/dev/stderr"
        # print "==> episodeDescription from
 = \n" episodeDescription > "/dev/stderr"
        next
    }
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman/season:1/videos/gasmamman-episode-01-sn-1-ep-1-1";\
    #  "Gasmamman, S01E01, Gåsmamman: Episode 01 (Sn 1 Ep 1)")
    if ($0 ~ /<\/div>/) {
        # Make sure episodeDescription is valid
        if (episodeDescription == "") {
            if (episodeType == "T") {
                episodeDescription = episodeTitle
                # print "==> episodeDescription from title = " episodeDescription > "/dev/stderr"
            } else {
                print "==> No description: " shortEpisodeURL >> ERRORS
            }
        }
        if (episodeDescription ~ /^PR \|/)
            sub (/^PR \| /,"",episodeDescription)
        # print "==> episodeDescription = \n" episodeDescription > "/dev/stderr"
        #
        # Check for valid seasonNumber and episodeNumber before using them
        if (seasonNumber == "")
            printf ("==> Missing seasonNumber in \"%s: %s\"\n", showTitle, episodeTitle) >> ERRORS
        #
        episodeNumber = snEpisodeNumber
        if (cxEpisodeNumber != "")
            episodeNumber = cxEpisodeNumber
        if (prEpisodeNumber != "" && cxEpisodeNumber == "")
            episodeNumber = prEpisodeNumber
        #
        if (episodeNumber == "")
            printf ("==> Missing episodeNumber in \"%s: %s\"\n", showTitle, episodeTitle) >> ERRORS
        #
        episodeLink = sprintf ("=HYPERLINK(\"%s\";\"%s, S%02d%s%02d, %s\")", episodeURL, showTitle,
                    seasonNumber, episodeType, episodeNumber, episodeTitle)
        #
        # Make sure episodeDuration is valid
        if (split (episodeDuration, tm, ":") == 3) {
            # Canonicalize episodeDuration to 3 parts like other services
            episodeDuration = sprintf ("%02d:%02d:%02d",tm[1],tm[2],tm[3])
        } else {
            printf ("==> Bad episodeDuration %s in \"%s: %s\"\n", episodeDuration, showTitle,
                    episodeTitle) >> ERRORS
            episodeDuration = ""
        }
        #
        # Print "episode" line
        printf ("%s\t\t\t%s\t\t\t\t\t%s\n", episodeLink, episodeDuration, episodeDescription)
        #
        # Look for directors
        director_name = episodeDescription
        # Skip UTF-8 for now...
        # if (gsub (/\xc2\xa0/," ",director_name)) {
            # printf ("==> UTF-8 non-breaking-space in %s, S%02d%s%02d, %s\n", showTitle, seasonNumber,
                    # episodeType, episodeNumber, episodeTitle) >> ERRORS
            # print "    " episodeDescription >> ERRORS
        # }
        if (director_name ~ /[Dd]irected by /) {
            sub (/.*[Dd]irected by /,"",director_name)
            sub (/,.*$/,"",director_name)
            sub (/ [0-9][0-9][0-9][0-9]\./,"",director_name)
            sub (/[[:space:]]+$/,"",director_name)
            sub (/\.$/,"",director_name)
            # Special cases
            if (director_name ~ /Manetti Bros/)
                director_name = "The Manetti Bros."
            if (director_name ~ /Andrea and Antonio Frazzi/)
                director_name = "Andrea Frazzi and Antonio Frazzi"
            #
            if (match (director_name, " and ") || match (director_name, " & ")) {
                dname = substr(director_name,1,RSTART-1)
                director_name = substr(director_name,RSTART+RLENGTH)
                printf ("%s\tdirector\ttv_show\t%s\n", dname, showTitle) >> RAW_CREDITS
            }
            printf ("%s\tdirector\ttv_show\t%s\n", director_name, showTitle) >> RAW_CREDITS
        }
        # Make sure there is no carryover
        descriptionLinesFound = 0
        episodeLink = ""
        episodeURL =""
        shortEpisodeURL = ""
        episodeType = ""
        episodeNumber = ""
        cxEpisodeNumber = ""
        snEpisodeNumber = ""
        episodeTitle = ""
        episodeDuration = ""
        episodeDescription =""
    }
}

### Wrap-up show processing - print on standard out

# Footer at end of file
#
/ "/dev/stderr"
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman";"Gasmamman")
    showLink = "=HYPERLINK(\"" showURL "\";\"" showTitle "\")"
    #
    # Shows with only one season have a blank showSeasons
    if (showSeasons == "")
        showSeasons = 1
    # in most cases, showSeasons = the final season number, i.e.
    # a show with two seasons would have seasons 1 and 2
    finalSeason = showSeasons
    # Special case any discontinuous seasons, e.g. 2 seasons, but numbered 1 and 3
    if (showURL ~ /\/wallander$/)
        finalSeason = 3
    #
    # Wrap show, i.e. but only on final season in order to prevent multiples
    # print "==> " showURL " - seasonNumber = " seasonNumber  > "/dev/stderr"
    # print "==> " showTitle " - finalSeason = " finalSeason  > "/dev/stderr"
    if (seasonNumber > finalSeason ) {
        # This should be OK, as printing any single valid season will work - however ...
        printf ("==> Season number %d beyond final season %d: %s\n", seasonNumber, finalSeason,
                shortSeasonURL) >> ERRORS
    }
    if (seasonNumber == finalSeason ) {
        # Print "show" line
        printf ("%s\t%s\t\t\t%s\n", showLink, showSeasons, showDescriptor)
    }
    #
    #  =HYPERLINK("https://watch.mhzchoice.com/gasmamman/season:1";"Gasmamman, S01, Season 1")
    if (page2 != "yes") {
        seasonLink = sprintf ("=HYPERLINK(\"%s\";\"%s, S%02d, %s\")", seasonURL, showTitle, seasonNumber,
                   seasonTitle)
        # print "==> seasonURL = " seasonURL  > "/dev/stderr"
        # print "==> seasonLink = " seasonLink  > "/dev/stderr"
        # Don't print redundant showDescriptor for season 1
        if (seasonNumber == 1)
            showDescriptor = ""
        # Print "season" line
        printf ("%s\t\t%s\t\t%s\n", seasonLink, seasonEpisodes, showDescriptor)
    }
    #
    # Make sure there is no carryover
    showLink = ""
    showURL = ""
    showTitle = ""
    showSeasons = ""
    showDescriptor = ""
    # print "" > "/dev/stderr"
    #
    page2 = ""
    seasonLink = ""
    seasonURL = ""
    shortSeasonURL = ""
    seasonNumber = ""
    seasonTitle = ""
    seasonEpisodes = ""
}