summaryrefslogtreecommitdiff
path: root/cli/enigma.hs
blob: 4c0881e8177480103c746b1b12fbd1ba4c698b88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
{-# LANGUAGE Safe, CPP #-}
module Main where

import Options.Applicative                              -- http://hackage.haskell.org/package/optparse-applicative
import Options.Applicative.Help.Pretty  (string)        -- Necessary to format help text -- https://github.com/pcapriotti/optparse-applicative/issues/90#issuecomment-49868254
import System.Console.ANSI
import Data.Version (showVersion)

import Data.Monoid                      ((<>))          -- REV: For GHC 8.0 through 8.2
import Control.Concurrent               (threadDelay)
import Control.Monad                    (replicateM_)

import Crypto.Enigma
import Crypto.Enigma.Display
import Paths_crypto_enigma (version)



-- Definitions  ==============================================================


-- Functions and constants ---------------------------------------------------

cliName_ = "Enigma Machine (Haskell crypto-enigma) CLI"

#if __GLASGOW_HASKELL__ < 800
cliError e = error (e ++ " (see help)")
#else
cliError e = errorWithoutStackTrace (e ++ " (see help)")
#endif

stepInterval_ = 125000


-- Command and option definitions --------------------------------------------

data Subcommand =
        Encode { config :: String, message :: String } |
        Show { config :: String, letterO ::
                Maybe String, formatO :: Maybe String, highlightO :: Maybe String, encodingO :: Maybe Bool } |
        Run { config :: String, messageO ::
                Maybe String, formatO :: Maybe String, highlightO :: Maybe String, encodingO :: Maybe Bool,
                showstepsO :: Maybe Bool, numstepsO :: Int,
                speedO :: Int, overwriteO :: Maybe Bool, noinitialO :: Maybe Bool }
        deriving Show

data Options = Options { subcommand :: Subcommand } deriving Show

commandO = Options <$> subcommandO

subcommandO :: Parser Subcommand
subcommandO =
  subparser (
        command "encode" (info (Encode <$> configArg "encode" <*> messageArg
                                <**> helper)
                         (helpText encodeCmdDesc "ENCODE" encodeCmdArgsFoot encodeCmdExamples)) <>
        command "show"   (info (Show <$> configArg "show" <*> letterOpt <*>
                                formatOpt <*> highlightOpt <*> encodingOpt
                                <**> helper)
                         (helpText showCmdDesc "SHOW" showCmdArgsFoot showCmdExamples)) <>
        command "run"    (info (Run <$> configArg "run" <*> messageOpt <*>
                                formatOpt <*> highlightOpt <*> encodingOpt <*>
                                showstepOpt <*> stepsOpt <*>
                                speedOpt <*> overwriteOpt <*> noinitialOpt
                                <**> helper)
                         (helpText runCmdDesc "RUN" runCmdArgsFoot runCmdExamples))
   )
  where
        configArg cmd = strArgument $ metavar "CONFIG" <>
                help (configArgHelp cmd)
        messageArg = strArgument $ metavar "MESSAGE" <>
                help messageArgHelp
        messageOpt = optional $ strOption ( long "message" <> short 'm' <> metavar "MESSAGE" <> value " " <>
                help messageOptHelp)
        letterOpt =  optional $ strOption ( long "letter" <> short 'l' <> metavar "LETTER" <> value " " <>
                help letterOptHelp)
        formatOpt =  optional $ strOption ( long "format" <> short 'f' <> metavar "FORMAT" <> value "single" <>
                help formatOptHelp)
        highlightOpt =  optional $ strOption ( long "highlight" <> short 'H' <> metavar "HH|SPEC" <> value "bars" <>
                help highlightOptHelp)
        encodingOpt = optional $ switch ( long "showencoding" <> short 'e' <>
                help showencodingOptHelp)

        showstepOpt =  optional $ switch ( long "showstep" <> short 't' <>
                help "Show step numbers")
        stepsOpt :: Parser Int
        stepsOpt = option auto (long "steps" <> short 's' <> metavar "STEPS"  <> value (-1) <>
                help stepsOptHelp)

        speedOpt :: Parser Int
        speedOpt = option auto (long "speed" <> short 'S' <> metavar "SPEED"  <> value 0 <>
                help speedOptHelp)
        overwriteOpt = optional $ switch ( long "overwrite" <> short 'o' <>
                help overwriteOptHelp)

        noinitialOpt =  optional $ switch ( long "noinitial" <> short 'n' <>
                help noinitialOptHelp)

        helpText desc cmd argsFoot examplesFoot = (progDesc desc <>
                header (cliName_ ++ ": "++ cmd ++" command") <>
                footerDoc (Just $ string $ unlines ["Argument notes:\n", argsFoot, "Examples:\n", examplesFoot]))

versionOpt = infoOption (showVersion version) (long "version" <> short 'v' <> help "Show package version")



-- Command line script =======================================================


main :: IO ()
main = do
    opts <- execParser optsParser
    case subcommand opts of
        Encode config message ->
                        putStr $ displayEnigmaEncoding (configEnigmaFromString config)
                                message
        Show config (Just (letter:_))
                (Just format) (Just highlight) (Just showenc) ->
                        putStrLn $ displayEnigmaConfig (configEnigmaFromString config)
                                letter
                                (displayOpts{format=format,showencoding=showenc,markerspec=highlight})
        Run config (Just message)
                (Just format) (Just highlight) (Just showenc)
                (Just showstps) stps
                speed (Just overwrite) (Just noinitial) ->
                        mapM_ (printConfig (max speed (if overwrite then 1 else 0)) overwrite)
                                   ((if noinitial then tail else id) $ listEnigmaOperation (configEnigmaFromString config)
                                   message
                                   (displayOpts{format=format,showencoding=showenc,markerspec=highlight,
                                                showsteps=showstps,steps=stps}))
        cmd -> putStrLn $ "Unmatched command: " ++ (show cmd)
  where
    optsParser :: ParserInfo Options
    optsParser = info (helper <*> versionOpt <*> commandO)
                      (fullDesc <> progDesc topDesc <> header cliName_ <> footerDoc (Just $ string topFoot))

    -- Like 'configEnigma' but without stack trace and with check for 4 words in a single string
    configEnigmaFromString :: String -> EnigmaConfig
    configEnigmaFromString i = if ((length $ words i) /= 4)
                          then cliError ("Enigma machine configuration has the format 'rotors windows plugboard rings'")
                          else either (cliError.show) id (configEnigma' c w s r) where [c, w, s, r] = words i

    printConfig s True c = printConfig s False c >>
                                replicateM_ ((length $ lines c) + (if (length $ lines c) > 1 then 1 else 0))
                                            (cursorUpLine 1 >> clearLine)
    printConfig s False c = putStrLn c >>
                                (threadDelay (s * stepInterval_))



-- Help text =================================================================

topDesc = "A simple Enigma machine simulator with rich display of machine configurations."

encodeCmdDesc = "Show the encoding of a message."
showCmdDesc = "Show an Enigma machine configuration in the specified format, " ++
              "optionally indicating the encoding of a specified character."
runCmdDesc = "Show the operation of the Enigma machine as a series of configurations, " ++
             "as it encodes a message and/or for a specified number of steps. "

configArgHelp cmd = case cmd of
                        "encode" -> unlines ["The machine configuration at the start of encoding (see below)"]
                        "show" -> unlines ["The machine configuration to show (see below)"]
                        "run" -> unlines ["The machine setup at the start of operation (see below)"]
                        -- Should not happen: optparse-applicative should have caught this
                        _ -> error "ERROR: Unrecognized command: '" ++ cmd ++ "''!"

messageArgHelp = messageOptHelp

messageOptHelp = unlines [
         "A message to encode; characters that are not letters" ,
         "will be replaced with standard Naval substitutions or",
         "be removed"]

letterOptHelp = unlines [
         "An optional input letter to highlight as it is" ,
         "processed by the configuration; defaults to nothing"]

formatOptHelp = unlines [
         "The format used to display machine configuration(s)" ,
         "(see below)"]

highlightOptHelp = unlines [
         "Either a pair or characters to use to highlight encoded" ,
         "characters in a machine configuration's encoding or a" ,
         "specification of a color or style (see below)"]

showencodingOptHelp = unlines [
         "Show the encoding if not normally shown for the" ,
         "specified FORMAT"]

stepsOptHelp = unlines [
        "A number of steps to run; if omitted when a message is" ,
        "provided, will default to the length of the message;" ,
        "otherwise defaults to 1"]

speedOptHelp = unlines [
        "Pause between display of each step for SPEED*" ++ show ((fromIntegral stepInterval_) / 1000000) ++ "s;",
         "1 is the minimum and default speed with --overwrite; ",
         "defaults to 0 otherwise"]

overwriteOptHelp = unlines [
        "Overwrite each step after a pause (may result in" ,
        "garbled output on some systems)"]

noinitialOptHelp = unlines [
        "Don't show the initial starting step"]

encodeCmdArgsFoot = init $ unlines [configArgFoot, omitArgFoot "encode"]
showCmdArgsFoot = init $ unlines [configArgFoot, formatArgFoot "show", highlightArgFoot, omitArgFoot "show"]
runCmdArgsFoot = init $ unlines [configArgFoot, formatArgFoot "run", highlightArgFoot, omitArgFoot "run"]

configArgFoot = unlines [
        "CONFIG specifies an Enigma machine configuration as a string based on common",
        "historical conventions and consists of four elements, separated by spaces:",
        " + names for components, in physical order (starting with the reflector, on the",
        "   left, and ending with the 'first' rotor, on the right), separated by '-'s;",
        " + letters visible at the machine windows (in physical order);",
        " + a plugboard specification, consisting of exchanged (i.e. wired-together)",
        "   letter paris, separated by '.'s; and",
        " + the locations of ring letter A on the rotor for each rotor",
        "   (in physical order)"]

formatArgFoot cmd = unlines $ [
        "FORMAT will determine how a configuration is represented; possible values",
        "include:",
        " + 'single' (the default) which will show a single line representing the",
        "   mapping (a string in which the letter at each position indicates the letter",
        "   encoded to by letter at that position in the alphabet) preformed by the",
        "   machine as a whole, followed by window letters (as 'windows') and",
        "   positions, and indicating a letter and its encoding, if provided;",
        " + 'internal', which will show a detailed schematic of each processing stage",
        "   (proceeding from top to bottom), in which",
        "    - each line indicates the mapping (see 'single') preformed by the",
        "      component at that stage;",
        "    - each line begins with an indication of the stage (rotor number, \"P\" for",
        "      plugboard, or \"R\" for reflector), and ends with the specification of the",
        "      component at that stage;",
        "    - rotors also indicate their window letter, and position;",
        "    - the letter being encoded it is indicated as input and its encoding at",
        "      each stage is marked;",
        "   the schematic is followed by the mapping for the machine as a whole (as",
        "   'single'), and preceded by a (trivial, no-op) keyboard 'mapping'",
        "   for reference;",
        " + 'windows', which shows just the letters visible at the windows;",
        "    and",
        " + 'config', which simply shows the specification of the",
        "   configuration (in the same format as CONFIG).",
        "For formats that indicate a letter and its encoding, these will correspond to"]
        ++ letterSoruce ++
       ["The program is forgiving about forgotten format values and will accept a",
        "range of reasonable substitutes (e.g., 'detailed' or 'schematic' for",
        "'internal')."]
                where letterSoruce | cmd == "run" =
                                     ["the the letter at that step of the entry of the (symbol substituted) MESSAGE ",
                                      "provided as an argument."]
                                   | otherwise = ["the LETTER provided as an argument."]

highlightArgFoot = unlines [
        "HH can be used to determine how any encoded-to characters in mappings",
        "(see 'single' in the note on FORMAT) are highlighted. By default",
        "this highlighting is done with combining Unicode characters, which may not",
        "work on all systems, and as an alternative, any two characters provided as",
        "HH will be used to 'bracket' the highlighted character. To avoid errors,",
        "these characters should be enclosed in quotes. Additionally certain",
        "predefined SPEC values, such as 'red' or 'highlight' are also supported."]


omitArgFoot cmd = unlines [
        "Note that providing no value, a value of '', or just spaces or invalid",
        "characters for " ++ omittedArg ++ " is the same as omitting it."]
                where omittedArg | cmd == "show" = "LETTER"
                                 | otherwise = "MESSAGE"

topFoot = "Examples:\n" ++ topExamples ++ "\nThis command line interface is part of the Haskell crypto-enigma package."

topExamples = unlines [
        "    $ enigma encode \"B-I-III-I EMO UX.MO.AY 13.04.11\" \"TESTINGXTESTINGUD\"",
        "    $ enigma encode \"B-I-III-I EMO UX.MO.AY 13.04.11\" \"TESTING! testing?\"",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X'",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -H '()'",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -H '()' -f internal",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -s 10 -t",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()'",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()' -f internal",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()' -f internal -o -SS",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -f config -e",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -f internal -e",
        "    $ enigma run \"c-β-VIII-VII-VI QMLI UX.MO.AY 01.13.04.11\" -s 500 -t -f internal -o",
        "",
        "More information about each of these examples is available in the help for the respective",
        "commands."]

encodeCmdExamples = init $ unlines [
        "  Encode a message:",
        "    $ enigma encode \"B-I-III-I EMO UX.MO.AY 13.04.11\" \"TESTINGXTESTINGUD\"",
        "    OZQK PFLP YZRP YTFV U",
        "",
        "  Standard Naval subistitutions for non-letter characters are performed",
        "  before encoding:",
        "    $ enigma encode \"B-I-III-I EMO UX.MO.AY 13.04.11\" \"TESTING! testing?\"",
        "    OZQK PFLP YZRP YTFV U"]

showCmdExamples = init $ unlines [
        "  Show an Enigma machine configuration as its mapping (see 'single'",
        "  in the note on FORMAT), followed by the window letters and ring settings,",
        "  and indicate how a letter is encoded; here X is encoded to T (A would be",
        "  encoded to C, B to N ... Y to W, Z to O):",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X'",
        "    X > CNAUJVQSLEMIKBZRGPHXDFYT̲̅WO  EMO  19 10 05",
        "",
        "  Use an alternate method for highlighting the encoded-to letter:",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -H '()'",
        "    X > CNAUJVQSLEMIKBZRGPHXDFY(T)WO  EMO  19 10 05",
        "",
        "  Show a detailed stage-by-stage schematic (see 'internal' in the note",
        "  on FORMAT) of the mappings preformed by a configuration:",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -H '()' -f internal",
        "    X > ABCDEFGHIJKLMNOPQRSTUVW(X)YZ",
        "      P YBCDEFGHIJKLONMPQRSTXVW(U)AZ         UX.MO.AY",
        "      1 HCZMRVJPKSUDTQOLWEXN(Y)FAGIB  O  05  I",
        "      2 KOMQEPVZNXRBDLJHFSUWYACT(G)I  M  10  III",
        "      3 AXIQJZ(K)RMSUNTOLYDHVBWEGPFC  E  19  I",
        "      R YRUHQSLDPX(N)GOKMIEBFZCWVJAT         B",
        "      3 ATZQVYWRCEGOI(L)NXDHJMKSUBPF         I",
        "      2 VLWMEQYPZOA(N)CIBFDKRXSGTJUH         III",
        "      1 WZBLRVXAYGIPD(T)OHNEJMKFQSUC         I",
        "      P YBCDEFGHIJKLONMPQRS(T)XVWUAZ         UX.MO.AY",
        "    T < CNAUJVQSLEMIKBZRGPHXDFY(T)WO",
        "",
        "  Just show the configuration in conventional format (as used in CONFIG):",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -f config",
        "    B-I-III-I EMO UX.MO.AY 13.04.11",
        "",
        "  As above, but show the encoding too (not shown my default for 'config'):",
        "    $ enigma show \"B-I-III-I EMO UX.MO.AY 13.04.11\" -l 'X' -f config -e",
        "    B-I-III-I EMO UX.MO.AY 13.04.11  X > T"]

runCmdExamples = init $ unlines [
        "(For details on differences among formats used for displaying each step, see the",
        "examples in the examples for the 'show' command.)",
        "",
        "  Show the operation of a machine for 10 steps, indicating step numbers (see",
        "  'single' in the note on FORMAT):",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -s 10 -t",
        "    0000      CNAUJVQSLEMIKBZRGPHXDFYTWO  EMO  19 10 05",
        "    0001      UNXKGVERLYDIQBTWMHZOAFPCJS  EMP  19 10 06",
        "    0002      QTYJZXUPKDIMLSWHAVNBGROFCE  EMQ  19 10 07",
        "    0003      DMXAPTRWKYINBLUESGQFOZHCJV  ENR  19 11 08",
        "    0004      IUSMHRPEAQTVDYWGJFCKBLOZNX  ENS  19 11 09",
        "    0005      WMVXQRLSPYOGBTKIEFHNZCADJU  ENT  19 11 10",
        "    0006      WKIQXNRSCVBOYFLUDGHZPJAEMT  ENU  19 11 11",
        "    0007      RVPTWSLKYXHGNMQCOAFDZBEJIU  ENV  19 11 12",
        "    0008      IYTKRVSMALDJHZWXUEGCQFOPBN  ENW  19 11 13",
        "    0009      PSWGMODULZVIERFAXNBYHKCQTJ  ENX  19 11 14",
        "    0010      IVOWZKHGARFSPUCMXJLYNBDQTE  ENY  19 11 15",
        "",
        "  Show the operation of a machine as it encodes a message, with step numbers:",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()'",
        "    0000       CNAUJVQSLEMIKBZRGPHXDFYTWO   EMO  19 10 05",
        "    0001  T > UNXKGVERLYDIQBTWMHZ(O)AFPCJS  EMP  19 10 06",
        "    0002  E > QTYJ(Z)XUPKDIMLSWHAVNBGROFCE  EMQ  19 10 07",
        "    0003  S > DMXAPTRWKYINBLUESG(Q)FOZHCJV  ENR  19 11 08",
        "    0004  T > IUSMHRPEAQTVDYWGJFC(K)BLOZNX  ENS  19 11 09",
        "    0005  I > WMVXQRLS(P)YOGBTKIEFHNZCADJU  ENT  19 11 10",
        "    0006  N > WKIQXNRSCVBOY(F)LUDGHZPJAEMT  ENU  19 11 11",
        "    0007  G > RVPTWS(L)KYXHGNMQCOAFDZBEJIU  ENV  19 11 12",
        "",
        "  Show the operation of a machine as it encodes a message in more detail (see",
        "  'internal' in the note on FORMAT), with step numbers (only some",
        "  steps shown here):",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()' -f internal",
        "    0000",
        "    ...",
        "    0001",
        "    T > ABCDEFGHIJKLMNOPQRS(T)UVWXYZ",
        "      P YBCDEFGHIJKLONMPQRS(T)XVWUAZ         UX.MO.AY",
        "      1 BYLQUIOJRTCSPNKVDWM(X)EZFHAG  P  06  I",
        "      2 KOMQEPVZNXRBDLJHFSUWYAC(T)GI  M  10  III",
        "      3 AXIQJZKRMSUNTOLYDHV(B)WEGPFC  E  19  I",
        "      R Y(R)UHQSLDPXNGOKMIEBFZCWVJAT         B",
        "      3 ATZQVYWRCEGOILNXD(H)JMKSUBPF         I",
        "      2 VLWMEQY(P)ZOANCIBFDKRXSGTJUH         III",
        "      1 YAKQUWZXFHOCSNG(M)DILJEPRTBV         I",
        "      P YBCDEFGHIJKL(O)NMPQRSTXVWUAZ         UX.MO.AY",
        "    O < UNXKGVERLYDIQBTWMHZ(O)AFPCJS",
        "    ...",
        "    0007",
        "    G > ABCDEF(G)HIJKLMNOPQRSTUVWXYZ",
        "      P YBCDEF(G)HIJKLONMPQRSTXVWUAZ         UX.MO.AY",
        "      1 IDLNWM(J)HEPXQGRYTZBUAVSFKOC  V  12  I",
        "      2 NLPDOUYMW(Q)ACKIGERTVXZBSFHJ  N  11  III",
        "      3 AXIQJZKRMSUNTOLY(D)HVBWEGPFC  E  19  I",
        "      R YRU(H)QSLDPXNGOKMIEBFZCWVJAT         B",
        "      3 ATZQVYW(R)CEGOILNXDHJMKSUBPF         I",
        "      2 KVLDPXOYNZMBHAECJ(Q)WRFSITGU         III",
        "      1 TRZBIWMHAGXCFDYJ(L)NVPSUEKOQ         I",
        "      P YBCDEFGHIJK(L)ONMPQRSTXVWUAZ         UX.MO.AY",
        "    L < RVPTWS(L)KYXHGNMQCOAFDZBEJIU",
        "",
        "  Show the steps as above, but (slowly) in place (if the platform supports it)",
        "  rather than on a new line for each; only the last step is visible on",
        "  completion (as shown here):",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -H '()' -f internal -o -SS",
        "    0007",
        "    G > ABCDEF(G)HIJKLMNOPQRSTUVWXYZ",
        "      P YBCDEF(G)HIJKLONMPQRSTXVWUAZ         UX.MO.AY",
        "      1 IDLNWM(J)HEPXQGRYTZBUAVSFKOC  V  12  I",
        "      2 NLPDOUYMW(Q)ACKIGERTVXZBSFHJ  N  11  III",
        "      3 AXIQJZKRMSUNTOLY(D)HVBWEGPFC  E  19  I",
        "      R YRU(H)QSLDPXNGOKMIEBFZCWVJAT         B",
        "      3 ATZQVYW(R)CEGOILNXDHJMKSUBPF         I",
        "      2 KVLDPXOYNZMBHAECJ(Q)WRFSITGU         III",
        "      1 TRZBIWMHAGXCFDYJ(L)NVPSUEKOQ         I",
        "      P YBCDEFGHIJK(L)ONMPQRSTXVWUAZ         UX.MO.AY",
        "    L < RVPTWS(L)KYXHGNMQCOAFDZBEJIU",
        "",
        "  Stepping a configuration only changes the window letters:",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -f config -e",
        "    0000  B-I-III-I EMO UX.MO.AY 13.04.11",
        "    0001  B-I-III-I EMP UX.MO.AY 13.04.11  T > O",
        "    0002  B-I-III-I EMQ UX.MO.AY 13.04.11  E > Z",
        "    0003  B-I-III-I ENR UX.MO.AY 13.04.11  S > Q",
        "    0004  B-I-III-I ENS UX.MO.AY 13.04.11  T > K",
        "    0005  B-I-III-I ENT UX.MO.AY 13.04.11  I > P",
        "    0006  B-I-III-I ENU UX.MO.AY 13.04.11  N > F",
        "    0007  B-I-III-I ENV UX.MO.AY 13.04.11  G > L",
        "    $ enigma run \"B-I-III-I EMO UX.MO.AY 13.04.11\" -m \"TESTING\" -t -f windows -e",
        "    0000  EMO",
        "    0001  EMP  T > O",
        "    0002  EMQ  E > Z",
        "    0003  ENR  S > Q",
        "    0004  ENS  T > K",
        "    0005  ENT  I > P",
        "    0006  ENU  N > F",
        "    0007  ENV  G > L",
        "",
        "   Watch the machine run for 500 steps:",
        "    $ enigma run \"c-β-VIII-VII-VI QMLI UX.MO.AY 01.13.04.11\" -s 500 -t -f internal -o"]