{
  "id": "P077",
  "slug": "text-banner",
  "key": "P077-text-banner",
  "title": "Text banner",
  "summary": "Big letters five rows high from a built-in font, wrapped to the screen; ordinary text wrapped greedily to a width and lined up left, centred or right; and a frame whose width comes from the longest line, so its edge closes exactly.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P077 - Text banner\n\nBig letters five rows high, wrapped to fit the screen. Ordinary text\nwrapped to a width and lined up left, centred or right. And a frame round\nit that fits the text exactly.\n\n- `main.eml` - the menu, reading text and widths, and printing\n- `banner.eml` - the 5 x 5 font, big letters, wrapping, lining up and\n  framing\n\nHow each part works:\n\n- Big letters: a font of 41 glyphs (A to Z, 0 to 9, space and ! ? . -),\n  each five rows of five columns, with no two alike. Small letters are\n  drawn as capitals. A banner line is the glyphs side by side with one\n  space between, and no spaces left at the ends of the rows. 13 letters\n  fit in 80 columns, so longer text is wrapped first.\n- Wrapping is greedy: as many words as fit on each line, one space\n  between them. A word longer than the width is cut into pieces that\n  fit.\n- Lining up: right puts the spaces in front; centre splits them, with an\n  odd one going on the right. Nothing is added after the text.\n- The frame, as in the corpus case `text-banner-builder`, is as wide as\n  the longest line plus the padding on both sides, worked out from the\n  text rather than a fixed number. A wrong count would show as a ragged\n  right edge.\n\nWhat is checked: menu choices 1 to 4; text of up to 200 characters, and\nfor big letters only the characters the font has; a width of 10 to 80\n(10 to 70 inside a frame); padding of 0 to 4; left, centre or right. An\nempty answer cancels.\n\nSessions: `sessions/basic.in` gives:\n- \"Hello EML 2026!\" in big letters on two lines, and \"eml-p rocks?\" in\n  capitals;\n- one sentence wrapped to 30 on the left, and to 20 centred;\n- a sentence with \"internationalisation,\" cut to fit 15, on the right;\n- a sentence in a frame, 24 wide with padding 2, centred.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- \"a,b\", which the font cannot draw, and cancels;\n- widths 9, 81 and x, the alignment \"middle\", padding 5, then \"abc\" in\n  the smallest frame;\n- a text over 200 characters.\n\nBuilt on the verified corpus case `text-banner-builder` (sequence\nrepetition, and a frame drawn to a width taken from the longest line).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P077 text banner: big five-row letters, wrapped to the screen; ordinary\n# text wrapped to a width and lined up left, centred or right; and a frame\n# round it.\nimport banner\n\ndef trim(s):\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef number(s):\n    if len(s) == 0 or len(s) > 2:\n        return -1\n    0 => n\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef ask(prompt, low, high):\n    while True:\n        trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \")) => a\n        if a == \"\":\n            return -1\n        number(a) => n\n        if n >= low and n <= high:\n            return n\n        (\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\") ^0\n\ndef ask_text(prompt):\n    while True:\n        trim(input(prompt)) => s\n        if s == \"\" or len(s) <= 200:\n            return s\n        \"Up to 200 characters.\" ^0\n\ndef big():\n    while True:\n        ask_text(\"text for the banner> \") => s\n        if s == \"\":\n            \"Cancelled.\" ^0\n            return\n        if banner.can_draw(s):\n            # 13 letters of 5 columns, a space between them, fit in 80.\n            banner.wrap(s, 13) => parts\n            for k in [0:len(parts) - 1]:\n                if k > 0:\n                    \"\" ^0\n                for row in banner.big(parts[k]):\n                    row ^0\n            return\n        \"The big letters are A to Z, 0 to 9, space and ! ? . -\" ^0\n\ndef ask_how():\n    while True:\n        trim(input(\"line up (left, centre or right)> \")) => h\n        if h == \"\":\n            return \"\"\n        if h == \"left\" or h == \"centre\" or h == \"right\":\n            return h\n        \"Type left, centre or right.\" ^0\n\ndef wrapped():\n    ask_text(\"text> \") => s\n    if s == \"\":\n        \"Cancelled.\" ^0\n        return\n    ask(\"width\", 10, 80) => w\n    if w == -1:\n        \"Cancelled.\" ^0\n        return\n    ask_how() => how\n    if how == \"\":\n        \"Cancelled.\" ^0\n        return\n    \"+\" + \"-\" * (w - 2) + \"+\" => ruler\n    ruler ^0\n    for line in banner.wrap(s, w):\n        banner.aligned(line, w, how) ^0\n    ruler ^0\n    (\"(the rule marks the width, \" + str(w) + \" columns)\") ^0\n\ndef framed():\n    ask_text(\"text> \") => s\n    if s == \"\":\n        \"Cancelled.\" ^0\n        return\n    ask(\"width of the text\", 10, 70) => w\n    if w == -1:\n        \"Cancelled.\" ^0\n        return\n    ask(\"padding\", 0, 4) => pad\n    if pad == -1:\n        \"Cancelled.\" ^0\n        return\n    ask_how() => how\n    if how == \"\":\n        \"Cancelled.\" ^0\n        return\n    banner.wrap(s, w) => lines\n    0 => widest\n    for line in lines:\n        if len(line) > widest:\n            len(line) => widest\n    [] => placed\n    for line in lines:\n        placed + [banner.aligned(line, widest, how)] => placed\n    for row in banner.boxed(placed, pad):\n        row ^0\n\n\"== Text banner ==\" ^0\n\"Big letters, wrapped and lined-up text, and a frame that fits.\" ^0\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) big letters  2) wrap and line up  3) in a frame  4) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        big()\n    elif choice == \"2\":\n        wrapped()\n    elif choice == \"3\":\n        framed()\n    elif choice == \"4\":\n        False => running\n    else:\n        \"Pick a number from 1 to 4.\" ^0\n\"Bye.\" ^0\n",
      "python": "import banner\n\ndef trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef number(s):\n    if len(s) == 0 or len(s) > 2:\n        return -1\n    n = 0\n    for c in s:\n        if not (c >= \"0\" and c <= \"9\"):\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef ask(prompt, low, high):\n    while True:\n        a = trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \"))\n        if a == \"\":\n            return -1\n        n = number(a)\n        if n >= low and n <= high:\n            return n\n        print(\"Type a whole number from \" + str(low) + \" to \" + str(high) + \".\")\n\ndef ask_text(prompt):\n    while True:\n        s = trim(input(prompt))\n        if s == \"\" or len(s) <= 200:\n            return s\n        print(\"Up to 200 characters.\")\n\ndef big():\n    while True:\n        s = ask_text(\"text for the banner> \")\n        if s == \"\":\n            print(\"Cancelled.\")\n            return\n        if banner.can_draw(s):\n            parts = banner.wrap(s, 13)\n            for k in range(0, len(parts)):\n                if k > 0:\n                    print(\"\")\n                for row in banner.big(parts[k]):\n                    print(row)\n            return\n        print(\"The big letters are A to Z, 0 to 9, space and ! ? . -\")\n\ndef ask_how():\n    while True:\n        h = trim(input(\"line up (left, centre or right)> \"))\n        if h == \"\":\n            return \"\"\n        if h == \"left\" or h == \"centre\" or h == \"right\":\n            return h\n        print(\"Type left, centre or right.\")\n\ndef wrapped():\n    s = ask_text(\"text> \")\n    if s == \"\":\n        print(\"Cancelled.\")\n        return\n    w = ask(\"width\", 10, 80)\n    if w == -1:\n        print(\"Cancelled.\")\n        return\n    how = ask_how()\n    if how == \"\":\n        print(\"Cancelled.\")\n        return\n    ruler = \"+\" + \"-\" * (w - 2) + \"+\"\n    print(ruler)\n    for line in banner.wrap(s, w):\n        print(banner.aligned(line, w, how))\n    print(ruler)\n    print(\"(the rule marks the width, \" + str(w) + \" columns)\")\n\ndef framed():\n    s = ask_text(\"text> \")\n    if s == \"\":\n        print(\"Cancelled.\")\n        return\n    w = ask(\"width of the text\", 10, 70)\n    if w == -1:\n        print(\"Cancelled.\")\n        return\n    pad = ask(\"padding\", 0, 4)\n    if pad == -1:\n        print(\"Cancelled.\")\n        return\n    how = ask_how()\n    if how == \"\":\n        print(\"Cancelled.\")\n        return\n    lines = banner.wrap(s, w)\n    widest = 0\n    for line in lines:\n        if len(line) > widest:\n            widest = len(line)\n    placed = []\n    for line in lines:\n        placed = placed + [banner.aligned(line, widest, how)]\n    for row in banner.boxed(placed, pad):\n        print(row)\n\nprint(\"== Text banner ==\")\nprint(\"Big letters, wrapped and lined-up text, and a frame that fits.\")\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) big letters  2) wrap and line up  3) in a frame  4) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        big()\n    elif choice == \"2\":\n        wrapped()\n    elif choice == \"3\":\n        framed()\n    elif choice == \"4\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 4.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "banner.eml",
      "eml": "# P077 text banner - big letters five rows high, text wrapped to a width\n# and lined up left, centred or right, and a frame drawn round it whose\n# width comes from the longest line, as in the corpus case\n# text-banner-builder - so a wrong count shows as a ragged edge.\n\n\"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !?.-\" => LETTERS\n\"abcdefghijklmnopqrstuvwxyz\" => SMALL\n\n[\n    [\" ### \", \"#   #\", \"#####\", \"#   #\", \"#   #\"],\n    [\"#### \", \"#   #\", \"#### \", \"#   #\", \"#### \"],\n    [\" ####\", \"#    \", \"#    \", \"#    \", \" ####\"],\n    [\"#### \", \"#   #\", \"#   #\", \"#   #\", \"#### \"],\n    [\"#####\", \"#    \", \"#### \", \"#    \", \"#####\"],\n    [\"#####\", \"#    \", \"#### \", \"#    \", \"#    \"],\n    [\" ####\", \"#    \", \"#  ##\", \"#   #\", \" ####\"],\n    [\"#   #\", \"#   #\", \"#####\", \"#   #\", \"#   #\"],\n    [\"#####\", \"  #  \", \"  #  \", \"  #  \", \"#####\"],\n    [\"#####\", \"   # \", \"   # \", \"#  # \", \" ##  \"],\n    [\"#   #\", \"#  # \", \"###  \", \"#  # \", \"#   #\"],\n    [\"#    \", \"#    \", \"#    \", \"#    \", \"#####\"],\n    [\"#   #\", \"## ##\", \"# # #\", \"#   #\", \"#   #\"],\n    [\"#   #\", \"##  #\", \"# # #\", \"#  ##\", \"#   #\"],\n    [\" ### \", \"#   #\", \"#   #\", \"#   #\", \" ### \"],\n    [\"#### \", \"#   #\", \"#### \", \"#    \", \"#    \"],\n    [\" ### \", \"#   #\", \"# # #\", \"#  # \", \" ## #\"],\n    [\"#### \", \"#   #\", \"#### \", \"#  # \", \"#   #\"],\n    [\" ####\", \"#    \", \" ### \", \"    #\", \"#### \"],\n    [\"#####\", \"  #  \", \"  #  \", \"  #  \", \"  #  \"],\n    [\"#   #\", \"#   #\", \"#   #\", \"#   #\", \" ### \"],\n    [\"#   #\", \"#   #\", \"#   #\", \" # # \", \"  #  \"],\n    [\"#   #\", \"#   #\", \"# # #\", \"## ##\", \"#   #\"],\n    [\"#   #\", \" # # \", \"  #  \", \" # # \", \"#   #\"],\n    [\"#   #\", \" # # \", \"  #  \", \"  #  \", \"  #  \"],\n    [\"#####\", \"   # \", \"  #  \", \" #   \", \"#####\"],\n    [\" ### \", \"#  ##\", \"# # #\", \"##  #\", \" ### \"],\n    [\"  #  \", \" ##  \", \"  #  \", \"  #  \", \" ### \"],\n    [\" ### \", \"#   #\", \"  ## \", \" #   \", \"#####\"],\n    [\"#### \", \"    #\", \" ### \", \"    #\", \"#### \"],\n    [\"#   #\", \"#   #\", \"#####\", \"    #\", \"    #\"],\n    [\"#####\", \"#    \", \"#### \", \"    #\", \"#### \"],\n    [\" ### \", \"#    \", \"#### \", \"#   #\", \" ### \"],\n    [\"#####\", \"    #\", \"   # \", \"  #  \", \"  #  \"],\n    [\" ### \", \"#   #\", \" ### \", \"#   #\", \" ### \"],\n    [\" ### \", \"#   #\", \" ####\", \"    #\", \" ### \"],\n    [\"     \", \"     \", \"     \", \"     \", \"     \"],\n    [\"  #  \", \"  #  \", \"  #  \", \"     \", \"  #  \"],\n    [\" ### \", \"#   #\", \"  ## \", \"     \", \"  #  \"],\n    [\"     \", \"     \", \"     \", \"     \", \"  #  \"],\n    [\"     \", \"     \", \"#####\", \"     \", \"     \"],\n] => GLYPHS\n\ndef index_in(s, c):\n    for i in [0:len(s) - 1]:\n        if s[i] == c:\n            return i\n    return -1\n\ndef upper(c):\n    index_in(SMALL, c) => i\n    if i >= 0:\n        return LETTERS[i]\n    return c\n\ndef can_draw(text):\n    for c in text:\n        if index_in(LETTERS, upper(c)) == -1:\n            return False\n    return True\n\ndef trim_right(s):\n    len(s) => j\n    while j > 0 and s[j - 1] == \" \":\n        j - 1 => j\n    return s[0:j]\n\ndef big(text):\n    # Five rows: each letter's glyph, one space between letters, and no\n    # spaces left at the ends of the rows.\n    [\"\", \"\", \"\", \"\", \"\"] => rows\n    for k in [0:len(text) - 1]:\n        GLYPHS[index_in(LETTERS, upper(text[k]))] => g\n        for r in [0:4]:\n            if k > 0:\n                rows[r] + \" \" => rows[r]\n            rows[r] + g[r] => rows[r]\n    for r in [0:4]:\n        trim_right(rows[r]) => rows[r]\n    return rows\n\ndef words(s):\n    [] => out\n    \"\" => w\n    for c in s + \" \":\n        if c == \" \":\n            if w != \"\":\n                out + [w] => out\n            \"\" => w\n        else:\n            w + c => w\n    return out\n\ndef wrap(text, width):\n    # Greedy wrapping: as many words as fit on each line, one space between\n    # them; a word longer than the width is cut into pieces that fit.\n    [] => lines\n    \"\" => line\n    for w in words(text):\n        while len(w) > width:\n            if line != \"\":\n                lines + [line] => lines\n                \"\" => line\n            lines + [w[0:width]] => lines\n            w[width:len(w)] => w\n        if line == \"\":\n            w => line\n        elif len(line) + 1 + len(w) <= width:\n            line + \" \" + w => line\n        else:\n            lines + [line] => lines\n            w => line\n    if line != \"\":\n        lines + [line] => lines\n    return lines\n\ndef aligned(line, width, how):\n    # The line placed in the width: \"left\", \"centre\" (an odd space left\n    # over goes on the right) or \"right\". Nothing is added after the text.\n    0 => left\n    if how == \"right\":\n        width - len(line) => left\n    elif how == \"centre\":\n        int((width - len(line) - (width - len(line)) % 2) / 2) => left\n    return \" \" * left + line\n\ndef boxed(lines, pad):\n    # The corpus case's frame: as wide as the longest line plus the\n    # padding on both sides, so the right edge closes exactly.\n    0 => widest\n    for line in lines:\n        if len(line) > widest:\n            len(line) => widest\n    widest + pad * 2 => inner\n    [\"+\" + \"-\" * inner + \"+\"] => out\n    for line in lines:\n        out + [\"|\" + \" \" * pad + line + \" \" * (inner - pad - len(line)) + \"|\"] => out\n    return out + [\"+\" + \"-\" * inner + \"+\"]\n",
      "python": "LETTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 !?.-\"\nSMALL = \"abcdefghijklmnopqrstuvwxyz\"\nGLYPHS = [[\" ### \", \"#   #\", \"#####\", \"#   #\", \"#   #\"], [\"#### \", \"#   #\", \"#### \", \"#   #\", \"#### \"], [\" ####\", \"#    \", \"#    \", \"#    \", \" ####\"], [\"#### \", \"#   #\", \"#   #\", \"#   #\", \"#### \"], [\"#####\", \"#    \", \"#### \", \"#    \", \"#####\"], [\"#####\", \"#    \", \"#### \", \"#    \", \"#    \"], [\" ####\", \"#    \", \"#  ##\", \"#   #\", \" ####\"], [\"#   #\", \"#   #\", \"#####\", \"#   #\", \"#   #\"], [\"#####\", \"  #  \", \"  #  \", \"  #  \", \"#####\"], [\"#####\", \"   # \", \"   # \", \"#  # \", \" ##  \"], [\"#   #\", \"#  # \", \"###  \", \"#  # \", \"#   #\"], [\"#    \", \"#    \", \"#    \", \"#    \", \"#####\"], [\"#   #\", \"## ##\", \"# # #\", \"#   #\", \"#   #\"], [\"#   #\", \"##  #\", \"# # #\", \"#  ##\", \"#   #\"], [\" ### \", \"#   #\", \"#   #\", \"#   #\", \" ### \"], [\"#### \", \"#   #\", \"#### \", \"#    \", \"#    \"], [\" ### \", \"#   #\", \"# # #\", \"#  # \", \" ## #\"], [\"#### \", \"#   #\", \"#### \", \"#  # \", \"#   #\"], [\" ####\", \"#    \", \" ### \", \"    #\", \"#### \"], [\"#####\", \"  #  \", \"  #  \", \"  #  \", \"  #  \"], [\"#   #\", \"#   #\", \"#   #\", \"#   #\", \" ### \"], [\"#   #\", \"#   #\", \"#   #\", \" # # \", \"  #  \"], [\"#   #\", \"#   #\", \"# # #\", \"## ##\", \"#   #\"], [\"#   #\", \" # # \", \"  #  \", \" # # \", \"#   #\"], [\"#   #\", \" # # \", \"  #  \", \"  #  \", \"  #  \"], [\"#####\", \"   # \", \"  #  \", \" #   \", \"#####\"], [\" ### \", \"#  ##\", \"# # #\", \"##  #\", \" ### \"], [\"  #  \", \" ##  \", \"  #  \", \"  #  \", \" ### \"], [\" ### \", \"#   #\", \"  ## \", \" #   \", \"#####\"], [\"#### \", \"    #\", \" ### \", \"    #\", \"#### \"], [\"#   #\", \"#   #\", \"#####\", \"    #\", \"    #\"], [\"#####\", \"#    \", \"#### \", \"    #\", \"#### \"], [\" ### \", \"#    \", \"#### \", \"#   #\", \" ### \"], [\"#####\", \"    #\", \"   # \", \"  #  \", \"  #  \"], [\" ### \", \"#   #\", \" ### \", \"#   #\", \" ### \"], [\" ### \", \"#   #\", \" ####\", \"    #\", \" ### \"], [\"     \", \"     \", \"     \", \"     \", \"     \"], [\"  #  \", \"  #  \", \"  #  \", \"     \", \"  #  \"], [\" ### \", \"#   #\", \"  ## \", \"     \", \"  #  \"], [\"     \", \"     \", \"     \", \"     \", \"  #  \"], [\"     \", \"     \", \"#####\", \"     \", \"     \"]]\n\ndef index_in(s, c):\n    for i in range(0, len(s)):\n        if s[i] == c:\n            return i\n    return -1\n\ndef upper(c):\n    i = index_in(SMALL, c)\n    if i >= 0:\n        return LETTERS[i]\n    return c\n\ndef can_draw(text):\n    for c in text:\n        if index_in(LETTERS, upper(c)) == -1:\n            return False\n    return True\n\ndef trim_right(s):\n    j = len(s)\n    while j > 0 and s[j - 1] == \" \":\n        j = j - 1\n    return s[0:j]\n\ndef big(text):\n    rows = [\"\", \"\", \"\", \"\", \"\"]\n    for k in range(0, len(text)):\n        g = GLYPHS[index_in(LETTERS, upper(text[k]))]\n        for r in range(0, 5):\n            if k > 0:\n                rows[r] = rows[r] + \" \"\n            rows[r] = rows[r] + g[r]\n    for r in range(0, 5):\n        rows[r] = trim_right(rows[r])\n    return rows\n\ndef words(s):\n    out = []\n    w = \"\"\n    for c in s + \" \":\n        if c == \" \":\n            if w != \"\":\n                out = out + [w]\n            w = \"\"\n        else:\n            w = w + c\n    return out\n\ndef wrap(text, width):\n    lines = []\n    line = \"\"\n    for w in words(text):\n        while len(w) > width:\n            if line != \"\":\n                lines = lines + [line]\n                line = \"\"\n            lines = lines + [w[0:width]]\n            w = w[width:len(w)]\n        if line == \"\":\n            line = w\n        elif len(line) + 1 + len(w) <= width:\n            line = line + \" \" + w\n        else:\n            lines = lines + [line]\n            line = w\n    if line != \"\":\n        lines = lines + [line]\n    return lines\n\ndef aligned(line, width, how):\n    left = 0\n    if how == \"right\":\n        left = width - len(line)\n    elif how == \"centre\":\n        left = int((width - len(line) - (width - len(line)) % 2) / 2)\n    return \" \" * left + line\n\ndef boxed(lines, pad):\n    widest = 0\n    for line in lines:\n        if len(line) > widest:\n            widest = len(line)\n    inner = widest + pad * 2\n    out = [\"+\" + \"-\" * inner + \"+\"]\n    for line in lines:\n        out = out + [\"|\" + \" \" * pad + line + \" \" * (inner - pad - len(line)) + \"|\"]\n    return out + [\"+\" + \"-\" * inner + \"+\"]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\na,b\n\n2\n\n2\nabc\n9\n81\nx\n20\nmiddle\n\n3\nabc\n10\n5\n0\nleft\n2\nword word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word\n\n4\n",
      "screen": "== Text banner ==\nBig letters, wrapped and lined-up text, and a frame that fits.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 0\nPick a number from 1 to 4.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> x\nPick a number from 1 to 4.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 1\ntext for the banner> a,b\nThe big letters are A to Z, 0 to 9, space and ! ? . -\ntext for the banner> \nCancelled.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> \nCancelled.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> abc\nwidth (10 to 80)> 9\nType a whole number from 10 to 80.\nwidth (10 to 80)> 81\nType a whole number from 10 to 80.\nwidth (10 to 80)> x\nType a whole number from 10 to 80.\nwidth (10 to 80)> 20\nline up (left, centre or right)> middle\nType left, centre or right.\nline up (left, centre or right)> \nCancelled.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 3\ntext> abc\nwidth of the text (10 to 70)> 10\npadding (0 to 4)> 5\nType a whole number from 0 to 4.\npadding (0 to 4)> 0\nline up (left, centre or right)> left\n+---+\n|abc|\n+---+\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word\nUp to 200 characters.\ntext> \nCancelled.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 4\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\nHello EML 2026!\n1\neml-p rocks?\n2\nThe quick brown fox jumps over the lazy dog, again and again.\n30\nleft\n2\nThe quick brown fox jumps over the lazy dog, again and again.\n20\ncentre\n2\nSome words are longer than a line: internationalisation, for one.\n15\nright\n3\nA frame as wide as its longest line, so the right edge closes.\n24\n2\ncentre\n4\n",
      "screen": "== Text banner ==\nBig letters, wrapped and lined-up text, and a frame that fits.\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 1\ntext for the banner> Hello EML 2026!\n#   # ##### #     #      ###        ##### #   # #\n#   # #     #     #     #   #       #     ## ## #\n##### ####  #     #     #   #       ####  # # # #\n#   # #     #     #     #   #       #     #   # #\n#   # ##### ##### #####  ###        ##### #   # #####\n\n ###   ###   ###   ###    #\n#   # #  ## #   # #       #\n  ##  # # #   ##  ####    #\n #    ##  #  #    #   #\n#####  ###  #####  ###    #\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 1\ntext for the banner> eml-p rocks?\n##### #   # #           ####        ####   ###   #### #   #  ####  ###\n#     ## ## #           #   #       #   # #   # #     #  #  #     #   #\n####  # # # #     ##### ####        ####  #   # #     ###    ###    ##\n#     #   # #           #           #  #  #   # #     #  #      #\n##### #   # #####       #           #   #  ###   #### #   # ####    #\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> The quick brown fox jumps over the lazy dog, again and again.\nwidth (10 to 80)> 30\nline up (left, centre or right)> left\n+----------------------------+\nThe quick brown fox jumps over\nthe lazy dog, again and again.\n+----------------------------+\n(the rule marks the width, 30 columns)\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> The quick brown fox jumps over the lazy dog, again and again.\nwidth (10 to 80)> 20\nline up (left, centre or right)> centre\n+------------------+\nThe quick brown fox\njumps over the lazy\n   dog, again and\n       again.\n+------------------+\n(the rule marks the width, 20 columns)\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 2\ntext> Some words are longer than a line: internationalisation, for one.\nwidth (10 to 80)> 15\nline up (left, centre or right)> right\n+-------------+\n Some words are\n  longer than a\n          line:\ninternationalis\nation, for one.\n+-------------+\n(the rule marks the width, 15 columns)\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 3\ntext> A frame as wide as its longest line, so the right edge closes.\nwidth of the text (10 to 70)> 24\npadding (0 to 4)> 2\nline up (left, centre or right)> centre\n+--------------------------+\n|  A frame as wide as its  |\n|   longest line, so the   |\n|    right edge closes.    |\n+--------------------------+\n\n1) big letters  2) wrap and line up  3) in a frame  4) quit\nchoice> 4\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "text-banner-builder",
      "caseId": "152-text-banner-builder",
      "title": "Sequence repetition"
    }
  ],
  "updated": "2026-10-14"
}
