jssm 5.35.4 → 5.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/.codeclimate.yml +22 -22
  2. package/.editorconfig +12 -12
  3. package/.eslintrc +20 -20
  4. package/.nycrc +6 -6
  5. package/.travis.yml +8 -8
  6. package/LICENSE.md +21 -21
  7. package/README.md +997 -993
  8. package/dist/es6/jssm-dot.d.ts +6 -6
  9. package/dist/es6/jssm-dot.js +1 -1
  10. package/dist/es6/jssm.d.ts +100 -100
  11. package/dist/es6/jssm.js +792 -792
  12. package/dist/es6/jssm_types.d.ts +151 -151
  13. package/dist/es6/jssm_types.js +1 -1
  14. package/dist/es6/jssm_util.d.ts +8 -8
  15. package/dist/es6/jssm_util.js +34 -34
  16. package/dist/es6/version.d.ts +2 -2
  17. package/dist/es6/version.js +2 -2
  18. package/dist/jssm.es5.cjs.js +1 -1
  19. package/dist/jssm.es5.iife.js +1 -0
  20. package/jest-spec.config.js +27 -27
  21. package/jest-stoch.config.js +27 -27
  22. package/jssm-dot.d.ts +6 -6
  23. package/jssm.d.ts +100 -100
  24. package/jssm_types.d.ts +151 -151
  25. package/jssm_util.d.ts +8 -8
  26. package/package.json +125 -122
  27. package/rollup.config.iife.js +44 -44
  28. package/rollup.config.js +44 -44
  29. package/src/demo/index.html +38 -38
  30. package/src/demo/style.css +1 -1
  31. package/src/ts/jssm-dot.peg +928 -874
  32. package/src/ts/jssm.ts +1120 -1120
  33. package/src/ts/jssm_types.ts +346 -346
  34. package/src/ts/jssm_util.ts +100 -100
  35. package/src/ts/tests/actions.spec.ts +167 -167
  36. package/src/ts/tests/arrange.spec.ts +72 -72
  37. package/src/ts/tests/arrange.stoch.ts +4 -4
  38. package/src/ts/tests/array_box_if_string.spec.ts +30 -31
  39. package/src/ts/tests/array_transitions.spec.ts +129 -129
  40. package/src/ts/tests/arrow unicode.spec.ts +88 -88
  41. package/src/ts/tests/arrow.spec.ts +124 -124
  42. package/src/ts/tests/colors.spec.ts +58 -58
  43. package/src/ts/tests/comment.spec.ts +134 -134
  44. package/src/ts/tests/compile.spec.ts +79 -79
  45. package/src/ts/tests/constants.spec.ts +98 -98
  46. package/src/ts/tests/cycles.spec.ts +153 -153
  47. package/src/ts/tests/dot_preamble.spec.ts +16 -16
  48. package/src/ts/tests/embedded_sm.spec.ts +36 -36
  49. package/src/ts/tests/flow.spec.ts +22 -22
  50. package/src/ts/tests/forced transitions.spec.ts +26 -26
  51. package/src/ts/tests/general.spec.ts +933 -933
  52. package/src/ts/tests/graph node lists.spec.ts +21 -21
  53. package/src/ts/tests/histo.spec.ts +24 -24
  54. package/src/ts/tests/hooks.spec.ts +28 -0
  55. package/src/ts/tests/language.spec.ts +37 -37
  56. package/src/ts/tests/language_data/belarussian.json +13 -13
  57. package/src/ts/tests/language_data/bengali.json +15 -15
  58. package/src/ts/tests/language_data/emoji.json +21 -21
  59. package/src/ts/tests/language_data/english.json +16 -16
  60. package/src/ts/tests/language_data/french.json +16 -16
  61. package/src/ts/tests/language_data/german.json +16 -16
  62. package/src/ts/tests/language_data/hebrew.json +16 -16
  63. package/src/ts/tests/language_data/portuguese.json +12 -12
  64. package/src/ts/tests/language_data/russian.json +12 -12
  65. package/src/ts/tests/language_data/spanish.json +17 -17
  66. package/src/ts/tests/language_data/ukrainian.json +18 -18
  67. package/src/ts/tests/layout.spec.ts +29 -29
  68. package/src/ts/tests/machine_attributes.spec.ts +398 -398
  69. package/src/ts/tests/machine_name.spec.ts +14 -14
  70. package/src/ts/tests/named lists.spec.ts +24 -19
  71. package/src/ts/tests/nominated states.spec.ts +133 -133
  72. package/src/ts/tests/parse actions.spec.ts +32 -32
  73. package/src/ts/tests/parse.spec.ts +94 -94
  74. package/src/ts/tests/probability.spec.ts +146 -146
  75. package/src/ts/tests/r639.spec.ts +27 -27
  76. package/src/ts/tests/sample_select.spec.ts +173 -173
  77. package/src/ts/tests/seq.spec.ts +14 -16
  78. package/src/ts/tests/seq.stoch.ts +83 -0
  79. package/src/ts/tests/shapes.spec.ts +63 -63
  80. package/src/ts/tests/sm_tag.spec.ts +37 -37
  81. package/src/ts/tests/special characters.spec.ts +39 -39
  82. package/src/ts/tests/state_declaration.spec.ts +214 -200
  83. package/src/ts/tests/state_style.spec.ts +82 -39
  84. package/src/ts/tests/stop light.spec.ts +157 -157
  85. package/src/ts/tests/stripes.spec.ts +52 -52
  86. package/src/ts/tests/theme.spec.ts +45 -45
  87. package/src/ts/tests/weighted_histo_key.spec.ts +22 -22
  88. package/src/ts/tests/weighted_rand_select.spec.ts +27 -27
  89. package/src/ts/tests/weighted_sample_select.spec.ts +24 -26
  90. package/src/ts/version.ts +1 -1
  91. package/tree.txt +1794 -1794
  92. package/tsconfig.json +27 -27
  93. package/version.d.ts +2 -2
package/README.md CHANGED
@@ -1,993 +1,997 @@
1
- # jssm
2
-
3
- Easy. Small. Fast. TS, es6, es5. Node, Browser. 100% coverage. Property
4
- tests. Fuzz tests. Language tests for a dozen languages and emoji. Easy to
5
- share online. Easy to embed.
6
-
7
- Readable, useful state machines as one-liner strings.
8
-
9
- ***Meet your new state machine library.***
10
-
11
- <a href="https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html" target="_blank" rel="noopener noreferrer">TRY THE LIVE EDITOR</a>
12
-
13
- <br/><br/>
14
-
15
- Wouldn't it be nice if your TypeScript and Javascript state machines were simple and readable one-liners?
16
-
17
- ```javascript
18
- import { sm } from 'jssm';
19
-
20
- const TrafficLight = sm`Red -> Green -> Yellow -> Red;`;
21
- ```
22
-
23
- <br/>
24
-
25
- Wouldn't it be great if they were easy to work with?
26
-
27
- ```javascript
28
- const log = s => console.log(s);
29
-
30
- log( TrafficLight.state() ); // 'Red'
31
-
32
- Machine.transition('Green'); // true
33
- log( TrafficLight.state() ); // 'Green'
34
- ```
35
-
36
- <br/>
37
-
38
- What if the notation supported action names easily?
39
-
40
- ```javascript
41
- const TrafficLightWithActions = sm`Red 'next' -> Green 'next' -> Yellow 'next' -> Red;`;
42
-
43
- log( TrafficLightWithActions.state() ); // 'Red'
44
-
45
- TrafficLightWithActions.action('next'); // true
46
- log( TrafficLightWithActions.state() ); // 'Green'
47
-
48
- TrafficLightWithActions.action('next'); // true
49
- log( TrafficLightWithActions.state() ); // 'Yellow'
50
-
51
- TrafficLightWithActions.action('next'); // true
52
- log( TrafficLightWithActions.state() ); // 'Red'
53
- ```
54
-
55
- <br/>
56
-
57
- What if the machine followed JS standards, and distinguished refusals as `false` from mistakes as `throw`n?
58
-
59
- ```javascript
60
- const AnotherTrafficLight = sm`Red -> Green -> Yellow -> Red;`;
61
-
62
- log( AnotherTrafficLight.state() ); // 'Red' - uses 1st state unless told otherwise
63
- AnotherTrafficLight.transition('Yellow'); // false (Yellow isn't allowed from Red)
64
- AnotherTrafficLight.transition('Blue'); // throws (Blue isn't a state at all)
65
- ```
66
-
67
- <br/>
68
-
69
- What if there were easy convenience notations for lists, and for designating main-path `=>` vs available path `->` vs
70
- only-when-forced `~>` ?
71
-
72
- ```javascript
73
- const TrafficLightWithOff = sm`
74
- Red => Green => Yellow => Red;
75
- [Red Yellow Green] ~> Off -> Red;
76
- `;
77
- ```
78
-
79
- <br/>
80
-
81
- What if that were easy to render visually?
82
-
83
- ```javascript
84
- const TrafficLightWithOff = sm`
85
- Red => Green => Yellow => Red;
86
- [Red Yellow Green] ~> Off -> Red;
87
- `;
88
- ```
89
-
90
- <br/>
91
-
92
- <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/doc%20light%20unstyled.png"/>
93
-
94
- <br/>
95
-
96
- What if that were easy to render visually, with styling, in PNG, JPEG, or SVG?
97
-
98
- ```javascript
99
- const TrafficLightWithOff = sm`
100
- Red => Green => Yellow => Red;
101
- [Red Yellow Green] ~> Off -> Red;
102
-
103
- flow: left;
104
-
105
- state Red : { background-color: pink; corners: rounded; };
106
- state Yellow : { background-color: lightyellow; corners: rounded; };
107
- state Green : { background-color: lightgreen; corners: rounded; };
108
-
109
- state Off : {
110
- background-color : steelblue;
111
- text-color : white;
112
- shape : octagon;
113
- linestyle : dashed;
114
- };
115
- `;
116
- ```
117
-
118
- <br/>
119
-
120
- <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/doc%20light%20styled.png"/>
121
-
122
- <br/>
123
-
124
- What if the machine was lighting fast, able to do tens of millions of transitions per second?
125
-
126
- <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/speed%20claim.png"/>
127
-
128
- <br/>
129
-
130
- * What if the machine and language had [extensive 100% test coverage](https://coveralls.io/github/StoneCypher/jssm)
131
- with [thousands of cases](https://github.com/StoneCypher/jssm/tree/main/src/ts/tests)?
132
- * What if the machine gave extensive Typescript introspection support?
133
- * What if the machine had been around and active since May 2017?
134
- * What if the machine was MIT licensed, end to end?
135
-
136
- But, above all else:
137
-
138
- `What if it was easy?`
139
-
140
-
141
-
142
-
143
-
144
- <br/><br/>
145
-
146
- # Introducing JSSM
147
-
148
- Meet JSSM: the <b><u>J</u></b>ava<b><u>s</u></b>cript <b><u>S</u></b>tate <b><u>M</u></b>achine.
149
-
150
- State machines can make your code cleaner, safer, and more trustworthy.
151
-
152
- And, with the right language, state machines can be easy and fun.
153
-
154
- <a href="https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html" target="_blank" rel="noopener noreferrer">TRY THE LIVE EDITOR</a>
155
-
156
-
157
-
158
- <br/>
159
-
160
- ## What is JSSM?
161
-
162
- JSSM is a Javascript state machine implementing [Finite State Language](https://fsl.tools/), with a terse DSL and a simple API.
163
- 100% test coverage; typed with Flowtype. MIT licensed.
164
-
165
- The NPM package includes pure `es6`, a `cjs es5` bundle, and `.d.ts` typings. The repository includes the original typescript, the bundle, the es6, documentation, tests, tutorials, and so on.
166
-
167
- [Try it live!](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html)
168
-
169
- Visualize with [jssm-viz](https://github.com/StoneCypher/jssm-viz), or at the command line with [jssm-viz-cli](https://github.com/StoneCypher/jssm-viz-cli).
170
-
171
- Language test cases for Belorussian, English, German, Hebrew, Italian, Russian, Spanish, Ukrainian, and Emoji. Please help to make sure that your language is well handled!
172
-
173
- <div id="badge_style_hook">
174
-
175
- [![Actions Status](https://github.com/StoneCypher/jssm/workflows/Node%20CI/badge.svg)](https://github.com/StoneCypher/jssm/actions)
176
-
177
- [![GitHub forks](https://img.shields.io/github/forks/StoneCypher/jssm.svg?style=social&label=Fork%20JSSM)]()
178
- [![GitHub watchers](https://img.shields.io/github/watchers/StoneCypher/jssm.svg?style=social&label=Watch%20JSSM)]()
179
- [![GitHub stars](https://img.shields.io/github/stars/StoneCypher/jssm.svg?style=social&label=JSSM%20Stars)]()
180
- [![GitHub followers](https://img.shields.io/github/followers/StoneCypher.svg?style=social&label=Follow%20StoneCypher)]()
181
-
182
- [![License](https://img.shields.io/npm/l/jssm.svg)](https://github.com/StoneCypher/jssm/blob/master/LICENSE.md)
183
- [![Open issues](https://img.shields.io/github/issues/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues)
184
- [![Closed issues](https://img.shields.io/github/issues-closed/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues?q=is%3Aissue+is%3Aclosed)
185
- [![Travis status](https://img.shields.io/travis/StoneCypher/jssm.svg)](https://travis-ci.org/StoneCypher/jssm)
186
- [![Coveralls status](https://img.shields.io/coveralls/StoneCypher/jssm.svg)](https://coveralls.io/github/StoneCypher/jssm)
187
-
188
- [![NPM version](https://img.shields.io/npm/v/jssm.svg)](https://www.npmjs.com/package/jssm)
189
- [![CDNjs version](https://img.shields.io/cdnjs/v/jquery.svg)](https://img.shields.io/cdnjs/v/jquery.svg)
190
- [![NPM downloads](https://img.shields.io/npm/dt/jssm.svg)](https://www.npmjs.com/package/jssm)
191
-
192
- <img src="https://starchart.cc/StoneCypher/jssm.svg" width="50%">
193
-
194
- </div>
195
-
196
-
197
-
198
- <br/><br/>
199
-
200
- ## TL;DR
201
- Specify finite state machines with a brief syntax. Run them; they're fast. Make mistakes; they're strict. Derive
202
- charts. Save and load states, and histories. Make machine factories to churn out dozens or thousands of instances.
203
- Impress friends and loved ones. Cure corns and callouses.
204
-
205
- ```fsl
206
- Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
207
- ```
208
-
209
- This will produce the following FSM (graphed with [jssm-viz](https://github.com/StoneCypher/jssm-viz)):
210
-
211
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
212
-
213
- You'll build an executable state machine.
214
-
215
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20traffic%20light%20console%20screenshot.png)
216
-
217
-
218
-
219
- <br/><br/>
220
-
221
- ## Why
222
-
223
- As usual, a valid question.
224
-
225
-
226
-
227
- <br/>
228
-
229
- ### Why state machines
230
-
231
- State machines are a method of making your software better able to prevent illegal states. Similar to type systems, SQL
232
- constraints, and linters, state machines are a way to teach the software to catch mistakes in ways you define, to help
233
- lead to better software.
234
-
235
- The major mechanism of a state machine is to define `states`, the `transitions` between them, and sometimes associated
236
- `data` and other niceties. The minor mechanism of state machines is to attach `actions` to the transitions, such that
237
- the state machine can partially run itself.
238
-
239
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
240
-
241
- So, to look at the same traffic light as above, you'll notice some things.
242
-
243
- 1. A sufficiently smart implementation will know that it's okay for `Green` to switch to `Yellow`, but not to `Red`
244
- 1. A sufficiently smart implementation knows there's no such thing as `Blue`
245
- 1. A sufficiently smart implementation knows that when in `Green`, to be told to `Proceed` means to go to `Yellow`, but
246
- when in `Yellow`, it means to go to `Red` instead
247
-
248
- Along with other common sense things, a good state machine implementation can help eliminate large classes of error in
249
- software. State machines are often applied when the stakes on having things correct are high.
250
-
251
-
252
-
253
- <br/>
254
-
255
- ### Why this implementation
256
-
257
- Brevity.
258
-
259
- High quality testing. JSSM has 100% coverage, and has partial stochastic test coverage.
260
-
261
- Feature parity, especially around the DSL and data control.
262
-
263
- Data integrity. JSSM allows a much stricter form of state machine than is common, with a relatively low performance
264
- and storage overhead. It also offers an extremely terse domain specific language (though it does not require said DSL)
265
- to produce state machines in otherwise comparatively tiny and easily read code.
266
-
267
-
268
-
269
- <br/><br/>
270
-
271
- ## Quick Start
272
-
273
- > A state machine in `JSSM` is defined in one of two ways: through the DSL, or through a datastructure.
274
-
275
- So yeah, let's start by getting some terminology out of the way, and then we can go right back to that impenetrable
276
- sentence, so that it'll make sense.
277
-
278
-
279
-
280
- <br/>
281
-
282
- ### Quick Terminology
283
-
284
- Finite state machines have been around forever, are used by everyone, and are hugely important. As a result, the
285
- terminology is a mess, is in conflict, and is very poorly chosen, in accordince with everything-is-horrible law.
286
-
287
- This section describes the terminology *as used by this library*. The author has done his best to choose a terminology
288
- that matches common use and will be familiar to most. Conflicts are explained in the following section, to keep this
289
- simple.
290
-
291
- For this quick overview, we'll define six basic concepts:
292
-
293
- 1. `Finite state machine`s
294
- 1. `Machine`s
295
- 1. `State`s
296
- 1. `Current state`
297
- 1. `Transition`s
298
- 1. `Action`s
299
-
300
- There's other stuff, of course, but these five are enough to wrap your head around `finite state machine`s.
301
-
302
-
303
-
304
- <br/>
305
-
306
- #### Basic concepts
307
-
308
- This is a trivial traffic light `FSM`, with three states, three transitions, and one action:
309
-
310
- ```fsl
311
- Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
312
- ```
313
-
314
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
315
-
316
- Let's review its pieces.
317
-
318
- * `finite state machine`s
319
- * A `finite state machine` (or `FSM`) is a collection of `state`s, and rules about how you can `transition` between
320
- the `state`s.
321
- * We tend to refer to a design for a machine as "an `FSM`."
322
- * In this example, the traffic light's structure is "a traffic light `FSM`."
323
-
324
- * `state`s
325
- * `FSM`s always have at least one `state`, and nearly always many `state`s
326
- * In this example,
327
- * the `state`s are **Red**, **Yellow**, and **Green**
328
- * Something made from this `FSM` will only ever be one of those colors - not, say, **Blue**
329
-
330
- * `machine`s
331
- * Single instances of an `FSM` are referred to as a `machine`
332
- * We might have a thousand instances of the traffic light designed above
333
- * We would say "My intersection has four `machines` of the standard three color light `FSM`."
334
-
335
- * `current state`
336
- * A `machine` has a `current state`, though an `FSM` does not
337
- * "This specific traffic light is currently **Red**"
338
- * Traffic lights in general do not have a current color, only specific lights
339
- * `FSM`s do not have a current state, only specific `machine`s
340
- * A given `machine` will always have exactly one `state` - never multiple, never none
341
-
342
- * `transitions`
343
- * `FSM`s nearly always have `transition`s
344
- * Transitions govern whether a `state` may be reached from another `state`
345
- * This restriction is much of the value of `FSM`s
346
- * In this example,
347
- * the `transition`s are
348
- * **Green** &rarr; **Yellow**
349
- * **Yellow** &rarr; **Red**
350
- * **Red** &rarr; **Green**
351
- * a `machine` whose `current state` is **Green** may switch to **Yellow**, because there is an appropriate transition
352
- * a `machine` whose `current state` is **Green** may not switch to **Red**, or to **Green** anew, because there is no
353
- such transition
354
- * A `machine` in **Yellow** which is told to `transition` to **Green** (which isn't legal) will know to refuse
355
- * This makes `FSM`s an effective tool for error prevention
356
-
357
- * `actions`
358
- * Many `FSM`s have `action`s, which represent events from the outside world.
359
- * In this example, there is only one action - **Proceed**
360
- * The `action` **Proceed** is available from all three colors
361
- * At any time we may indicate to this light to go to its next color, without
362
- taking the time to know what it is.
363
- * This allows `FSM`s like the light to self-manage.
364
- * A `machine` in **Yellow** which is told to take the `action` **Proceed** will
365
- know on its own to switch its `current state` to **Red**.
366
- * This makes `FSM`s an effective tool for complexity reduction
367
-
368
- Those six ideas in hand - `FSM`s, `state`s, `machine`s, `current state`, `transition`s, and `action`s - and you're ready
369
- to move forwards.
370
-
371
- One other quick definition - a `DSL`, or `domain specific language`, is when someone makes a language and embeds it into
372
- a different language, for the purpose of attacking a specific job. When `React` uses a precompiler to embed stuff that
373
- looks like HTML in Javascript, that's a DSL.
374
-
375
- This library implements a simple language for `defining finite state machine`s inside of strings. For example, this
376
- `DSL` defines that `'a -> b;'` actually means "create two states, create a transition between them, assign the first as
377
- the initial state", et cetera. That micro-language is the `DSL` that we'll be referring to a lot, coming up. This
378
- `DSL`'s formal name is `jssm-dot`, because it's a descendant-in-spirit of an older flowcharting language
379
- [DOT](http://www.graphviz.org/content/dot-language), from [graphviz](graphviz.org), which is also used to make the
380
- visualizations in [jssm-viz](https://github.com/StoneCypher/jssm-viz) by way of [viz-js](viz-js.com).
381
-
382
- Enough history lesson. On with the tooling.
383
-
384
-
385
-
386
- <br/>
387
-
388
- ### And now, that Quick Start we were talking about
389
-
390
- So let's put together a trivial four-state traffic light: the three colors, plus **Off**. This will give us an
391
- opportunity to go over the basic facilities in the language.
392
-
393
- At any time, you can take the code and put it into the
394
- [graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
395
- code as you see fit.
396
-
397
-
398
-
399
- <br/>
400
-
401
- #### 0: Lights always have an off state
402
-
403
- Our light will start in the **Off** `state`, with the ability to switch to the **Red** `state`.
404
-
405
- Since that's a normal, not-notable thing, we'll just make it a regular `-> legal transition`.
406
-
407
- ```fsl
408
- Off -> Red;
409
- ```
410
-
411
- We will give that `transition` an `action`, and call it **TurnOn**.
412
-
413
- ```fsl
414
- Off 'TurnOn' -> Red;
415
- ```
416
-
417
- So far, our machine is simple:
418
-
419
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20Red.png)
420
-
421
-
422
-
423
- <br/>
424
-
425
- #### 1: Traffic lights have a three-color cycle
426
-
427
- The main path of a traffic light is cycling from **Green** to **Yellow**, then to **Red**, then back again. Because
428
- this is the main path, we'll mark these steps `=> main transition`s.
429
-
430
- ```fsl
431
- Off 'TurnOn' -> Red => Green => Yellow => Red;
432
- ```
433
-
434
- We will give those all the same action name, **Proceed**, indicating "next color" without needing to know what we're
435
- currently on.
436
-
437
- ```fsl
438
- Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
439
- ```
440
-
441
- Machine's still pretty simple:
442
-
443
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20RGY.png)
444
-
445
-
446
-
447
- <br/>
448
-
449
- #### 2: Traffic lights can be shut down
450
-
451
- We'd also like to be able to turn this light back off. Because that's expected to be a rarity, we'll require that it
452
- be a `~> forced transition`.
453
-
454
- We could write
455
-
456
- ```fsl
457
- Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
458
- Red ~> Off;
459
- Yellow ~> Off;
460
- Green ~> Off;
461
- ```
462
-
463
- But that takes a lot of space even with this short list, so, instead we'll use the array notation
464
-
465
- ```fsl
466
- Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
467
- [Red Yellow Green] ~> Off;
468
- ```
469
-
470
- And we'd like those all to have the action **TurnOff**, so
471
-
472
- ```fsl
473
- Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
474
- [Red Yellow Green] 'TurnOff' ~> Off;
475
- ```
476
-
477
- Machine's still not too bad:
478
-
479
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20From%20RGY.png)
480
-
481
-
482
-
483
- <br/>
484
-
485
- ### Let's actually use the traffic light
486
-
487
- That's actually the bulk of the language. There are other little add-ons here and there, but, primarily you now know
488
- how to write a state machine.
489
-
490
- Let's load it and use it! 😀
491
-
492
- #### loading into node
493
- #### loading into html
494
- #### jssm-viz
495
- #### redistribution on npm
496
-
497
-
498
-
499
- <br/>
500
-
501
- ### An introduction to machine design
502
-
503
- Let's make a `state machine` for ATMs. In the process, we will use a lot of core concepts of `finite state machine`s
504
- and of `jssm-dot`, this library's `DSL`.
505
-
506
- We're going to improve on this [NCSU ATM diagram](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif) that I
507
- found:
508
-
509
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/ncsu%20atm%20diagram.gif)
510
-
511
- Remember, at any time, you can take the code and put it into the
512
- [graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
513
- code as you see fit.
514
-
515
-
516
-
517
- <br/>
518
-
519
- #### 0: Empty machine
520
-
521
- We'll start with an [empty machine](https://github.com/StoneCypher/jssm/blob/master/src/machines/atm%20quick%20start%20tutorial/1_EmptyWaiting.jssm).
522
-
523
- ```fsl
524
- EmptyWaiting 'Wait' -> EmptyWaiting;
525
- ```
526
-
527
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/0_EmptyWaiting.png)
528
-
529
-
530
-
531
- <br/>
532
-
533
- #### 1: Should be able to eject cards
534
-
535
- We'll add the ability to physically eject the user's card and reset to the empty and waiting state. Right now it'll
536
- dangle around un-used at the top, but later it'll become useful.
537
-
538
- This is expressed as the path `EjectCardAndReset -> EmptyWaiting;`
539
-
540
- ```fsl
541
- EmptyWaiting 'Wait' -> EmptyWaiting;
542
- EjectCardAndReset -> EmptyWaiting;
543
- ```
544
-
545
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/1_EjectCard.png)
546
-
547
-
548
-
549
- <br/>
550
-
551
- #### 2: Should be able to insert cards
552
-
553
- We'll add the ability to physically insert a card, next. You know, the, uh, thing ATMs are pretty much for.
554
-
555
- To get this, add the path leg `EmptyWaiting 'InsertCard' -> HasCardNoAuth;`
556
-
557
- ```fsl
558
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
559
- EjectCardAndReset -> EmptyWaiting;
560
- ```
561
-
562
- Notice that the new `state`, **HasCardNoAuth**, has been rendered red. This is because it is `terminal` - there is
563
- no exit from this node currently. (**EmptyAndWaiting** did not render that way because it had a transition to itself.)
564
- That will change as we go back to adding more nodes. `terminal node`s are usually either mistakes or the last single
565
- `state` of a given `FSM`.
566
-
567
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/2_InsertCard.png)
568
-
569
-
570
-
571
- <br/>
572
-
573
- #### 3: Should be able to cancel and recover the card
574
-
575
- Next, we should have a cancel, because the ATM's <key>7</key> key is broken, and we need our card back. Cancel will
576
- exit to the main menu, and return our card credential.
577
-
578
- To that end, we add the path `HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;`
579
-
580
- ```fsl
581
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
582
-
583
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
584
-
585
- EjectCardAndReset -> EmptyWaiting;
586
- ```
587
-
588
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/3_ReturnCard.png)
589
-
590
-
591
-
592
- <br/>
593
-
594
- #### 4: Can give the wrong PIN
595
-
596
- Next, let's give the ability to get the password ... wrong. 😂 Because we all know that one ATM that only has the
597
- wrong-PIN path, so, apparently that's a product to someone.
598
-
599
- When they get the PIN wrong, they're prompted to try again (or to cancel.)
600
-
601
- We'll add the path `HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;`
602
-
603
- ```fsl
604
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
605
-
606
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
607
- HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
608
-
609
- EjectCardAndReset -> EmptyWaiting;
610
- ```
611
-
612
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/4_WrongPin.png)
613
-
614
-
615
-
616
-
617
-
618
- <br/>
619
-
620
- #### 5: Can give the correct PIN
621
-
622
- Next, let's give the ability to get the password right.
623
-
624
- We'll add two paths. The first gets the password right: `HasCardNoAuth 'RightPIN' -> MainMenu;`
625
-
626
- The second, from our new `state` **MainMenu**, gives people the ability to leave: `MainMenu 'ExitReturnCard' -> EjectCardAndReset;`
627
-
628
-
629
- ```fsl
630
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
631
-
632
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
633
- HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
634
- HasCardNoAuth 'RightPIN' -> MainMenu;
635
-
636
- MainMenu 'ExitReturnCard' -> EjectCardAndReset;
637
-
638
- EjectCardAndReset -> EmptyWaiting;
639
- ```
640
-
641
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/5_RightPin.png)
642
-
643
-
644
-
645
- <br/>
646
-
647
- #### 6: Can check balance from main menu
648
-
649
- Hooray, now we're getting somewhere.
650
-
651
- Let's add the ability to check your balance. First pick that from the main menu, then pick which account to see the
652
- balance of, then you're shown a screen with the information you requested; then go back to the main menu.
653
-
654
- That's `MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;`.
655
-
656
- ```fsl
657
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
658
-
659
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
660
- HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
661
- HasCardNoAuth 'RightPIN' -> MainMenu;
662
-
663
- MainMenu 'ExitReturnCard' -> EjectCardAndReset;
664
- MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;
665
-
666
- EjectCardAndReset -> EmptyWaiting;
667
- ```
668
-
669
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/6_CanCheckBalance.png)
670
-
671
-
672
-
673
- <br/>
674
-
675
- #### 7: Can deposit money from main menu
676
-
677
- Let's add something difficult. Their state machine just proceeds assuming everything is okay.
678
-
679
- To desposit money:
680
-
681
- 1. Accept physical money
682
- 2. If accept failed (eg door jammed,) reject physical object, go to main menu
683
- 3. If accept succeeded, ask human expected value
684
- 4. Pick an account this should go into
685
- 5. Contact bank. Request to credit for theoretical physical money.
686
- 6. Three results: yes, no, offer-after-audit.
687
- 7. If no, reject physical object, go to main menu.
688
- 8. If yes, consume physical object, tell user consumed, go to main menu
689
- 9. If offer-after-audit, ask human what to do
690
- 10. if human-yes, consume physical object, tell user consumed, go to main menu
691
- 11. if human-no, reject physical object, go to main menu
692
-
693
- Writing this out in code is not only generally longer than the text form, but also error prone and hard to maintain.
694
-
695
- ... or there's the `FSM` `DSL`, which is usually as-brief-as the text, and frequently both briefer and more explicit.
696
-
697
- * Rules 1-2: `MainMenu 'AcceptDeposit' -> TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;`
698
- * Rules 3-6: `TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;`
699
- * Rule 7: `BankResponse 'BankNo' -> RejectPhysicalMoney;`
700
- * Rule 8: `BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;`
701
- * Rules 9-10: `BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;`
702
- * Rule 11: `BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;`
703
-
704
- Or, as a block,
705
-
706
- ```fsl
707
- MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
708
-
709
- TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
710
- TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
711
-
712
- BankResponse 'BankNo' -> RejectPhysicalMoney;
713
- BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
714
- BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
715
-
716
- BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
717
- ```
718
-
719
- Which leaves us with the total code
720
-
721
-
722
- ```fsl
723
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
724
-
725
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
726
- HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
727
- HasCardNoAuth 'RightPIN' -> MainMenu;
728
-
729
- MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
730
- MainMenu 'ExitReturnCard' -> EjectCardAndReset;
731
- MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
732
-
733
- TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
734
- TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
735
-
736
- BankResponse 'BankNo' -> RejectPhysicalMoney;
737
- BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
738
- BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
739
-
740
- BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
741
-
742
- EjectCardAndReset -> EmptyWaiting;
743
- ```
744
-
745
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/7_CanDepositMoney.png)
746
-
747
-
748
-
749
- <br/>
750
-
751
- #### 8: Can withdraw money from main menu
752
-
753
- Let's also be able to take money from the machine. After this, we'll move on, since our example is pretty squarely made
754
- by now.
755
-
756
- 1. Pick a withdrawl account, or cancel to the main menu
757
- 2. Shown a balance, pick a withdrawl amount, or cancel to acct picker
758
- 3. Is the withdrawl account too high? If so go to 2
759
- 4. Does the machine actually have the money? If not go to 2
760
- 5. Otherwise confirm intent w/ human
761
- 6. Attempt to post the transaction.
762
- 7. If fail, display reason and go to 1
763
- 8. If succeed, dispense money and go to main menu
764
-
765
- * Rules 1-3: `MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;`
766
- * Rule 4: `AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;`
767
- * Rule 5: `MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;`
768
- * Rule 6: `ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;`
769
- * Rule 7: `BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;`
770
- * Rule 8: `BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;`
771
-
772
- Rule 1 canceller: `PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;`
773
- Rule 2 canceller: `PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;`
774
-
775
- Or as a whole, we're adding
776
-
777
- ```fsl
778
- MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
779
- AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
780
- MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
781
- ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
782
- BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
783
- BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
784
-
785
- PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
786
- PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
787
- ```
788
-
789
- Which leaves us with
790
-
791
- ```fsl
792
- EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
793
-
794
- HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
795
- HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
796
- HasCardNoAuth 'RightPIN' -> MainMenu;
797
-
798
- MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
799
- MainMenu 'ExitReturnCard' -> EjectCardAndReset;
800
- MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
801
-
802
- TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
803
- TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
804
-
805
- BankResponse 'BankNo' -> RejectPhysicalMoney;
806
- BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
807
- BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
808
-
809
- BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
810
-
811
- MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
812
- AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
813
- MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
814
- ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
815
- BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
816
- BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
817
-
818
- PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
819
- PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
820
-
821
- EjectCardAndReset -> EmptyWaiting;
822
- ```
823
-
824
- ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/8_CanWithdrawMoney.png)
825
-
826
- As you can see, building up even very complex state machines is actually relatively straightforward, in a short
827
- amount of time.
828
-
829
-
830
-
831
- <br/><br/>
832
-
833
- ## Features
834
- ### DSL
835
- ### States
836
- ### Transitions
837
- ### Cycles
838
- ### Stripes
839
- ### Named Ordered Lists
840
- ### Atoms
841
- ### Strings
842
- ### Arrow types
843
- ### Unicode representations
844
- ### Node declarations
845
- ### All the styling bullshit
846
- ### Named edges
847
- ### URL callouts
848
- ### The 9 or whatever directives
849
- ### How to publish a machine
850
- #### Legal, main, and forced
851
- ### Validators
852
- ### State history
853
- ### Automatic visualization
854
-
855
-
856
-
857
- <br/><br/>
858
-
859
- ## How to think in state machines
860
-
861
-
862
-
863
- <br/><br/>
864
-
865
- ## Example Machines
866
- ### Door lock
867
- ### Traffic lights
868
- #### Basic three-state
869
- #### RYG, Off, Flash-red, Flash-yellow
870
- #### RYG, Off, Flash-red, Flash-yellow, Green-left, Yellow-left
871
- #### Heirarchal intersection
872
- ### [ATM](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif)
873
- ### [HTTP](https://www.w3.org/Library/User/Architecture/HTTP.gif)
874
- #### Better HTTP
875
- ### [TCP](http://www.texample.net/media/tikz/examples/PNG/tcp-state-machine.png)
876
- ### Coin-op vending machine (data)
877
- ### Video games
878
- #### Pac-man Ghost (sensors)
879
- #### Weather (probabilistics)
880
- #### Roguelike monster (interface satisfaction)
881
- ### Candy crush clone game flow (practical large use)
882
- ### Vegas locked 21 dealer behavior
883
- ### React SPA website (practical large use)
884
- ### [BGP](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/BGP_FSM.svg/549px-BGP_FSM.svg.png)
885
- ### [LibGCrypt FIPS mode FSM](https://www.gnupg.org/documentation/manuals/gcrypt/fips-fsm.png)
886
-
887
-
888
-
889
- <br/><br/>
890
-
891
- ## How to debug
892
-
893
-
894
-
895
- <br/><br/>
896
-
897
- ## How to publish
898
- It's really quite simple.
899
-
900
- 1. Make a github repository.
901
- 1. Put your code in a file inside, with the extension `.fsl`
902
- 1. Make sure your code contains a `machine_name`
903
-
904
- Once done, your work should show up [here](https://github.com/search?utf8=%E2%9C%93&q=extension%3Afsl+machine_name&type=Code).
905
-
906
-
907
-
908
- <br/><br/>
909
-
910
- ## Notation Comparison
911
- ### Their notations, one by one
912
- ### Apples to Apples - Traffic Light
913
-
914
-
915
-
916
- <br/><br/>
917
-
918
- ## Other state machines
919
- There are a lot of state machine impls for JS, many quite a bit more mature than this one. Here are some options:
920
-
921
- 1. [Finity](https://github.com/nickuraltsev/finity) 😮
922
- 1. [Stately.js](https://github.com/fschaefer/Stately.js)
923
- 1. [machina.js](https://github.com/ifandelse/machina.js)
924
- 1. [Pastafarian](https://github.com/orbitbot/pastafarian)
925
- 1. [Henderson](https://github.com/orbitbot/henderson)
926
- 1. [fsm-as-promised](https://github.com/vstirbu/fsm-as-promised)
927
- 1. [state-machine](https://github.com/DEADB17/state-machine)
928
- 1. [mood](https://github.com/bredele/mood)
929
- 1. [FSM Workbench](https://github.com/MatthewHepburn/FSM-Workbench)
930
- 1. [SimpleStateMachine](https://github.com/ccnokes/SimpleStateMachine)
931
- 1. shime/[micro-machine](https://github.com/shime/micro-machine)
932
- 1. soveran/[micromachine](https://github.com/soveran/micromachine) (ruby)
933
- 1. fabiospampinato/[FSM](https://github.com/fabiospampinato/FSM)
934
- 1. HQarroum/[FSM](https://github.com/HQarroum/Fsm)
935
- 1. [Finite-State-Automata](https://github.com/RolandR/Finite-State-Automata)
936
- 1. [finite-state-machine](https://github.com/MarkH817/finite-state-machine)
937
- 1. [nfm](https://github.com/ajauhri/nfm)
938
-
939
-
940
- And some similar stuff:
941
- 1. [redux-machine](https://github.com/mheiber/redux-machine)
942
- 1. [ember-fsm](https://github.com/heycarsten/ember-fsm)
943
- 1. [State machine cat](https://github.com/sverweij/state-machine-cat)
944
- 1. [Workty](https://github.com/AlexLevshin/workty) 😮
945
- 1. [sam-simpler](https://github.com/sladiri/sam-simpler)
946
- 1. [event_chain](https://github.com/quilin/event_chain)
947
- 1. [DRAKON](https://en.wikipedia.org/wiki/DRAKON)
948
- 1. [Yakindu Statechart Tools](https://github.com/Yakindu/statecharts)
949
- 1. [GraphViz](http://www.graphviz.org/)
950
- 1. [Viz.js](https://github.com/mdaines/viz.js/), which we use
951
-
952
-
953
-
954
- <br/><br/><br/>
955
-
956
- # Thanks
957
-
958
- JSSM and FSL have had a lot of help.
959
-
960
-
961
-
962
- <br/><br/>
963
-
964
- ## Internationalization
965
-
966
- * [Mykhaylo Les](https://github.com/miles91) provided three translation test cases ([Ukrainian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/ukrainian.json), [Belarussian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/belarussian.json), and [Russian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/russian.json),) and the corresponding Traffic Light translations (also [Ukrainian](https://github.com/StoneCypher/fsl_traffic_light_ukrainian/blob/master/traffic%20light.fsl), [Belarussian](https://github.com/StoneCypher/fsl_traffic_light_belarussian/blob/master/traffic_light.fsl), and [Russian](https://github.com/StoneCypher/fsl_traffic_light_russian/blob/master/traffic%20light.fsl).)
967
- * [Tanvir Islam](https://github.com/tanvirrb) provided the [Bengali test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/bengali.json), translated the [Traffic Light](https://github.com/tanvirrb/fsl-traffic-light-bengali/blob/master/traffic_light.fsl) to Bengali, and published the first non-English `FSL` machine, in Bengali.
968
- * [Francisco Junior](https://github.com/fcojr) provided the [Portuguese test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/portuguese.json) and translated the [Traffic Light](https://github.com/StoneCypher/fsl_traffic_light_portuguese/blob/master/traffic_light.fsl) to Portuguese
969
- * [Jeff Katz](https://github.com/kraln) provided the [German test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/german.json).
970
- * [Alex Cresswell](https://github.com/technophile77) provdied the [Spanish test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/spanish.json)
971
- * [Dvir Cohen](https://github.com/cohendvir) provided the [Hebrew test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/hebrew.json).
972
- * [David de la Peña](https://github.com/daviddelapena) provided the [French test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/french.json)
973
-
974
- If I've overlooked you, please let me know.
975
-
976
- If you'd like to help, it's straightforward.
977
-
978
- 1. Easy mode: open a PR with [this file](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/english.json) translated into your language
979
- 1. Extra mile: create a new repo containing [this file](https://github.com/StoneCypher/fsl_traffic_light/blob/master/traffic_light.fsl) translated
980
-
981
-
982
-
983
- <br/><br/>
984
-
985
- ## Code and Language
986
-
987
- [Forest Belton](https://github.com/forestbelton) has provided guidance, bugfixes, parser and language commentary.
988
-
989
- [Jordan Harbrand](https://github.com/ljharb) suggested two interesting features and provided strong feedback on the initial tutorial draft.
990
-
991
- The biggest thanks must go to [Michael Morgan](https://github.com/msmorgan/), who has debated significant sections of
992
- the notation, invented several concepts and operators, helped with the parser, with system nomenclature, for having published
993
- the first not-by-me `FSL` machine, for encouragement, and generally just for having been as interested as he has been.
1
+ # jssm
2
+
3
+ Easy. Small. Fast. TS, es6, es5. Node, Browser. 100% coverage. Property
4
+ tests. Fuzz tests. Language tests for a dozen languages and emoji. Easy to
5
+ share online. Easy to embed.
6
+
7
+ Readable, useful state machines as one-liner strings.
8
+
9
+ ***Meet your new state machine library.***
10
+
11
+ # <a href="https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html" target="_blank" rel="noopener noreferrer">TRY THE LIVE EDITOR</a>
12
+
13
+ <a href="https://discord.gg/9P95USqnMK">Discord community</a> - <a href="https://stonecypher.github.io/jssm/docs/">Documentation</a> - <a href="https://github.com/StoneCypher/fsl/issues">Issue tracker</a> - <a href="https://github.com/StoneCypher/jssm/actions">CI build history</a>
14
+
15
+ <a href="https://discord.gg/9P95USqnMK">![Discord community](https://discordapp.com/api/guilds/899910109642235924/widget.png?style=banner1)</a>
16
+
17
+ <br/><br/>
18
+
19
+ Wouldn't it be nice if your TypeScript and Javascript state machines were simple and readable one-liners?
20
+
21
+ ```javascript
22
+ import { sm } from 'jssm';
23
+
24
+ const TrafficLight = sm`Red -> Green -> Yellow -> Red;`;
25
+ ```
26
+
27
+ <br/>
28
+
29
+ Wouldn't it be great if they were easy to work with?
30
+
31
+ ```javascript
32
+ const log = s => console.log(s);
33
+
34
+ log( TrafficLight.state() ); // 'Red'
35
+
36
+ Machine.transition('Green'); // true
37
+ log( TrafficLight.state() ); // 'Green'
38
+ ```
39
+
40
+ <br/>
41
+
42
+ What if the notation supported action names easily?
43
+
44
+ ```javascript
45
+ const TrafficLightWithActions = sm`Red 'next' -> Green 'next' -> Yellow 'next' -> Red;`;
46
+
47
+ log( TrafficLightWithActions.state() ); // 'Red'
48
+
49
+ TrafficLightWithActions.action('next'); // true
50
+ log( TrafficLightWithActions.state() ); // 'Green'
51
+
52
+ TrafficLightWithActions.action('next'); // true
53
+ log( TrafficLightWithActions.state() ); // 'Yellow'
54
+
55
+ TrafficLightWithActions.action('next'); // true
56
+ log( TrafficLightWithActions.state() ); // 'Red'
57
+ ```
58
+
59
+ <br/>
60
+
61
+ What if the machine followed JS standards, and distinguished refusals as `false` from mistakes as `throw`n?
62
+
63
+ ```javascript
64
+ const AnotherTrafficLight = sm`Red -> Green -> Yellow -> Red;`;
65
+
66
+ log( AnotherTrafficLight.state() ); // 'Red' - uses 1st state unless told otherwise
67
+ AnotherTrafficLight.transition('Yellow'); // false (Yellow isn't allowed from Red)
68
+ AnotherTrafficLight.transition('Blue'); // throws (Blue isn't a state at all)
69
+ ```
70
+
71
+ <br/>
72
+
73
+ What if there were easy convenience notations for lists, and for designating main-path `=>` vs available path `->` vs
74
+ only-when-forced `~>` ?
75
+
76
+ ```javascript
77
+ const TrafficLightWithOff = sm`
78
+ Red => Green => Yellow => Red;
79
+ [Red Yellow Green] ~> Off -> Red;
80
+ `;
81
+ ```
82
+
83
+ <br/>
84
+
85
+ What if that were easy to render visually?
86
+
87
+ ```javascript
88
+ const TrafficLightWithOff = sm`
89
+ Red => Green => Yellow => Red;
90
+ [Red Yellow Green] ~> Off -> Red;
91
+ `;
92
+ ```
93
+
94
+ <br/>
95
+
96
+ <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/doc%20light%20unstyled.png"/>
97
+
98
+ <br/>
99
+
100
+ What if that were easy to render visually, with styling, in PNG, JPEG, or SVG?
101
+
102
+ ```javascript
103
+ const TrafficLightWithOff = sm`
104
+ Red => Green => Yellow => Red;
105
+ [Red Yellow Green] ~> Off -> Red;
106
+
107
+ flow: left;
108
+
109
+ state Red : { background-color: pink; corners: rounded; };
110
+ state Yellow : { background-color: lightyellow; corners: rounded; };
111
+ state Green : { background-color: lightgreen; corners: rounded; };
112
+
113
+ state Off : {
114
+ background-color : steelblue;
115
+ text-color : white;
116
+ shape : octagon;
117
+ linestyle : dashed;
118
+ };
119
+ `;
120
+ ```
121
+
122
+ <br/>
123
+
124
+ <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/doc%20light%20styled.png"/>
125
+
126
+ <br/>
127
+
128
+ What if the machine was lighting fast, able to do tens of millions of transitions per second?
129
+
130
+ <img src="https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/speed%20claim.png"/>
131
+
132
+ <br/>
133
+
134
+ * What if the machine and language had [extensive 100% test coverage](https://coveralls.io/github/StoneCypher/jssm)
135
+ with [thousands of cases](https://github.com/StoneCypher/jssm/tree/main/src/ts/tests)?
136
+ * What if the machine gave extensive Typescript introspection support?
137
+ * What if the machine had been around and active since May 2017?
138
+ * What if the machine was MIT licensed, end to end?
139
+
140
+ But, above all else:
141
+
142
+ `What if it was easy?`
143
+
144
+
145
+
146
+
147
+
148
+ <br/><br/>
149
+
150
+ # Introducing JSSM
151
+
152
+ Meet JSSM: the <b><u>J</u></b>ava<b><u>s</u></b>cript <b><u>S</u></b>tate <b><u>M</u></b>achine.
153
+
154
+ State machines can make your code cleaner, safer, and more trustworthy.
155
+
156
+ And, with the right language, state machines can be easy and fun.
157
+
158
+ <a href="https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html" target="_blank" rel="noopener noreferrer">TRY THE LIVE EDITOR</a>
159
+
160
+
161
+
162
+ <br/>
163
+
164
+ ## What is JSSM?
165
+
166
+ JSSM is a Javascript state machine implementing [Finite State Language](https://fsl.tools/), with a terse DSL and a simple API.
167
+ 100% test coverage; typed with Flowtype. MIT licensed.
168
+
169
+ The NPM package includes pure `es6`, a `cjs es5` bundle, and `.d.ts` typings. The repository includes the original typescript, the bundle, the es6, documentation, tests, tutorials, and so on.
170
+
171
+ [Try it live!](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html)
172
+
173
+ Visualize with [jssm-viz](https://github.com/StoneCypher/jssm-viz), or at the command line with [jssm-viz-cli](https://github.com/StoneCypher/jssm-viz-cli).
174
+
175
+ Language test cases for Belorussian, English, German, Hebrew, Italian, Russian, Spanish, Ukrainian, and Emoji. Please help to make sure that your language is well handled!
176
+
177
+ <div id="badge_style_hook">
178
+
179
+ [![Actions Status](https://github.com/StoneCypher/jssm/workflows/Node%20CI/badge.svg)](https://github.com/StoneCypher/jssm/actions)
180
+
181
+ [![GitHub forks](https://img.shields.io/github/forks/StoneCypher/jssm.svg?style=social&label=Fork%20JSSM)]()
182
+ [![GitHub watchers](https://img.shields.io/github/watchers/StoneCypher/jssm.svg?style=social&label=Watch%20JSSM)]()
183
+ [![GitHub stars](https://img.shields.io/github/stars/StoneCypher/jssm.svg?style=social&label=JSSM%20Stars)]()
184
+ [![GitHub followers](https://img.shields.io/github/followers/StoneCypher.svg?style=social&label=Follow%20StoneCypher)]()
185
+
186
+ [![License](https://img.shields.io/npm/l/jssm.svg)](https://github.com/StoneCypher/jssm/blob/master/LICENSE.md)
187
+ [![Open issues](https://img.shields.io/github/issues/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues)
188
+ [![Closed issues](https://img.shields.io/github/issues-closed/StoneCypher/jssm.svg)](https://github.com/StoneCypher/jssm/issues?q=is%3Aissue+is%3Aclosed)
189
+ [![Travis status](https://img.shields.io/travis/StoneCypher/jssm.svg)](https://travis-ci.org/StoneCypher/jssm)
190
+ [![Coveralls status](https://img.shields.io/coveralls/StoneCypher/jssm.svg)](https://coveralls.io/github/StoneCypher/jssm)
191
+
192
+ [![NPM version](https://img.shields.io/npm/v/jssm.svg)](https://www.npmjs.com/package/jssm)
193
+ [![CDNjs version](https://img.shields.io/cdnjs/v/jquery.svg)](https://img.shields.io/cdnjs/v/jquery.svg)
194
+ [![NPM downloads](https://img.shields.io/npm/dt/jssm.svg)](https://www.npmjs.com/package/jssm)
195
+
196
+ <img src="https://starchart.cc/StoneCypher/jssm.svg" width="50%">
197
+
198
+ </div>
199
+
200
+
201
+
202
+ <br/><br/>
203
+
204
+ ## TL;DR
205
+ Specify finite state machines with a brief syntax. Run them; they're fast. Make mistakes; they're strict. Derive
206
+ charts. Save and load states, and histories. Make machine factories to churn out dozens or thousands of instances.
207
+ Impress friends and loved ones. Cure corns and callouses.
208
+
209
+ ```fsl
210
+ Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
211
+ ```
212
+
213
+ This will produce the following FSM (graphed with [jssm-viz](https://github.com/StoneCypher/jssm-viz)):
214
+
215
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
216
+
217
+ You'll build an executable state machine.
218
+
219
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20traffic%20light%20console%20screenshot.png)
220
+
221
+
222
+
223
+ <br/><br/>
224
+
225
+ ## Why
226
+
227
+ As usual, a valid question.
228
+
229
+
230
+
231
+ <br/>
232
+
233
+ ### Why state machines
234
+
235
+ State machines are a method of making your software better able to prevent illegal states. Similar to type systems, SQL
236
+ constraints, and linters, state machines are a way to teach the software to catch mistakes in ways you define, to help
237
+ lead to better software.
238
+
239
+ The major mechanism of a state machine is to define `states`, the `transitions` between them, and sometimes associated
240
+ `data` and other niceties. The minor mechanism of state machines is to attach `actions` to the transitions, such that
241
+ the state machine can partially run itself.
242
+
243
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
244
+
245
+ So, to look at the same traffic light as above, you'll notice some things.
246
+
247
+ 1. A sufficiently smart implementation will know that it's okay for `Green` to switch to `Yellow`, but not to `Red`
248
+ 1. A sufficiently smart implementation knows there's no such thing as `Blue`
249
+ 1. A sufficiently smart implementation knows that when in `Green`, to be told to `Proceed` means to go to `Yellow`, but
250
+ when in `Yellow`, it means to go to `Red` instead
251
+
252
+ Along with other common sense things, a good state machine implementation can help eliminate large classes of error in
253
+ software. State machines are often applied when the stakes on having things correct are high.
254
+
255
+
256
+
257
+ <br/>
258
+
259
+ ### Why this implementation
260
+
261
+ Brevity.
262
+
263
+ High quality testing. JSSM has 100% coverage, and has partial stochastic test coverage.
264
+
265
+ Feature parity, especially around the DSL and data control.
266
+
267
+ Data integrity. JSSM allows a much stricter form of state machine than is common, with a relatively low performance
268
+ and storage overhead. It also offers an extremely terse domain specific language (though it does not require said DSL)
269
+ to produce state machines in otherwise comparatively tiny and easily read code.
270
+
271
+
272
+
273
+ <br/><br/>
274
+
275
+ ## Quick Start
276
+
277
+ > A state machine in `JSSM` is defined in one of two ways: through the DSL, or through a datastructure.
278
+
279
+ So yeah, let's start by getting some terminology out of the way, and then we can go right back to that impenetrable
280
+ sentence, so that it'll make sense.
281
+
282
+
283
+
284
+ <br/>
285
+
286
+ ### Quick Terminology
287
+
288
+ Finite state machines have been around forever, are used by everyone, and are hugely important. As a result, the
289
+ terminology is a mess, is in conflict, and is very poorly chosen, in accordince with everything-is-horrible law.
290
+
291
+ This section describes the terminology *as used by this library*. The author has done his best to choose a terminology
292
+ that matches common use and will be familiar to most. Conflicts are explained in the following section, to keep this
293
+ simple.
294
+
295
+ For this quick overview, we'll define six basic concepts:
296
+
297
+ 1. `Finite state machine`s
298
+ 1. `Machine`s
299
+ 1. `State`s
300
+ 1. `Current state`
301
+ 1. `Transition`s
302
+ 1. `Action`s
303
+
304
+ There's other stuff, of course, but these five are enough to wrap your head around `finite state machine`s.
305
+
306
+
307
+
308
+ <br/>
309
+
310
+ #### Basic concepts
311
+
312
+ This is a trivial traffic light `FSM`, with three states, three transitions, and one action:
313
+
314
+ ```fsl
315
+ Red 'Proceed' -> Green 'Proceed' -> Yellow 'Proceed' -> Red;
316
+ ```
317
+
318
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/ryg%20proceed.png)
319
+
320
+ Let's review its pieces.
321
+
322
+ * `finite state machine`s
323
+ * A `finite state machine` (or `FSM`) is a collection of `state`s, and rules about how you can `transition` between
324
+ the `state`s.
325
+ * We tend to refer to a design for a machine as "an `FSM`."
326
+ * In this example, the traffic light's structure is "a traffic light `FSM`."
327
+
328
+ * `state`s
329
+ * `FSM`s always have at least one `state`, and nearly always many `state`s
330
+ * In this example,
331
+ * the `state`s are **Red**, **Yellow**, and **Green**
332
+ * Something made from this `FSM` will only ever be one of those colors - not, say, **Blue**
333
+
334
+ * `machine`s
335
+ * Single instances of an `FSM` are referred to as a `machine`
336
+ * We might have a thousand instances of the traffic light designed above
337
+ * We would say "My intersection has four `machines` of the standard three color light `FSM`."
338
+
339
+ * `current state`
340
+ * A `machine` has a `current state`, though an `FSM` does not
341
+ * "This specific traffic light is currently **Red**"
342
+ * Traffic lights in general do not have a current color, only specific lights
343
+ * `FSM`s do not have a current state, only specific `machine`s
344
+ * A given `machine` will always have exactly one `state` - never multiple, never none
345
+
346
+ * `transitions`
347
+ * `FSM`s nearly always have `transition`s
348
+ * Transitions govern whether a `state` may be reached from another `state`
349
+ * This restriction is much of the value of `FSM`s
350
+ * In this example,
351
+ * the `transition`s are
352
+ * **Green** &rarr; **Yellow**
353
+ * **Yellow** &rarr; **Red**
354
+ * **Red** &rarr; **Green**
355
+ * a `machine` whose `current state` is **Green** may switch to **Yellow**, because there is an appropriate transition
356
+ * a `machine` whose `current state` is **Green** may not switch to **Red**, or to **Green** anew, because there is no
357
+ such transition
358
+ * A `machine` in **Yellow** which is told to `transition` to **Green** (which isn't legal) will know to refuse
359
+ * This makes `FSM`s an effective tool for error prevention
360
+
361
+ * `actions`
362
+ * Many `FSM`s have `action`s, which represent events from the outside world.
363
+ * In this example, there is only one action - **Proceed**
364
+ * The `action` **Proceed** is available from all three colors
365
+ * At any time we may indicate to this light to go to its next color, without
366
+ taking the time to know what it is.
367
+ * This allows `FSM`s like the light to self-manage.
368
+ * A `machine` in **Yellow** which is told to take the `action` **Proceed** will
369
+ know on its own to switch its `current state` to **Red**.
370
+ * This makes `FSM`s an effective tool for complexity reduction
371
+
372
+ Those six ideas in hand - `FSM`s, `state`s, `machine`s, `current state`, `transition`s, and `action`s - and you're ready
373
+ to move forwards.
374
+
375
+ One other quick definition - a `DSL`, or `domain specific language`, is when someone makes a language and embeds it into
376
+ a different language, for the purpose of attacking a specific job. When `React` uses a precompiler to embed stuff that
377
+ looks like HTML in Javascript, that's a DSL.
378
+
379
+ This library implements a simple language for `defining finite state machine`s inside of strings. For example, this
380
+ `DSL` defines that `'a -> b;'` actually means "create two states, create a transition between them, assign the first as
381
+ the initial state", et cetera. That micro-language is the `DSL` that we'll be referring to a lot, coming up. This
382
+ `DSL`'s formal name is `jssm-dot`, because it's a descendant-in-spirit of an older flowcharting language
383
+ [DOT](http://www.graphviz.org/content/dot-language), from [graphviz](graphviz.org), which is also used to make the
384
+ visualizations in [jssm-viz](https://github.com/StoneCypher/jssm-viz) by way of [viz-js](viz-js.com).
385
+
386
+ Enough history lesson. On with the tooling.
387
+
388
+
389
+
390
+ <br/>
391
+
392
+ ### And now, that Quick Start we were talking about
393
+
394
+ So let's put together a trivial four-state traffic light: the three colors, plus **Off**. This will give us an
395
+ opportunity to go over the basic facilities in the language.
396
+
397
+ At any time, you can take the code and put it into the
398
+ [graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
399
+ code as you see fit.
400
+
401
+
402
+
403
+ <br/>
404
+
405
+ #### 0: Lights always have an off state
406
+
407
+ Our light will start in the **Off** `state`, with the ability to switch to the **Red** `state`.
408
+
409
+ Since that's a normal, not-notable thing, we'll just make it a regular `-> legal transition`.
410
+
411
+ ```fsl
412
+ Off -> Red;
413
+ ```
414
+
415
+ We will give that `transition` an `action`, and call it **TurnOn**.
416
+
417
+ ```fsl
418
+ Off 'TurnOn' -> Red;
419
+ ```
420
+
421
+ So far, our machine is simple:
422
+
423
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20Red.png)
424
+
425
+
426
+
427
+ <br/>
428
+
429
+ #### 1: Traffic lights have a three-color cycle
430
+
431
+ The main path of a traffic light is cycling from **Green** to **Yellow**, then to **Red**, then back again. Because
432
+ this is the main path, we'll mark these steps `=> main transition`s.
433
+
434
+ ```fsl
435
+ Off 'TurnOn' -> Red => Green => Yellow => Red;
436
+ ```
437
+
438
+ We will give those all the same action name, **Proceed**, indicating "next color" without needing to know what we're
439
+ currently on.
440
+
441
+ ```fsl
442
+ Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
443
+ ```
444
+
445
+ Machine's still pretty simple:
446
+
447
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20RGY.png)
448
+
449
+
450
+
451
+ <br/>
452
+
453
+ #### 2: Traffic lights can be shut down
454
+
455
+ We'd also like to be able to turn this light back off. Because that's expected to be a rarity, we'll require that it
456
+ be a `~> forced transition`.
457
+
458
+ We could write
459
+
460
+ ```fsl
461
+ Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
462
+ Red ~> Off;
463
+ Yellow ~> Off;
464
+ Green ~> Off;
465
+ ```
466
+
467
+ But that takes a lot of space even with this short list, so, instead we'll use the array notation
468
+
469
+ ```fsl
470
+ Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
471
+ [Red Yellow Green] ~> Off;
472
+ ```
473
+
474
+ And we'd like those all to have the action **TurnOff**, so
475
+
476
+ ```fsl
477
+ Off 'TurnOn' -> Red 'Proceed' => Green 'Proceed' => Yellow 'Proceed' => Red;
478
+ [Red Yellow Green] 'TurnOff' ~> Off;
479
+ ```
480
+
481
+ Machine's still not too bad:
482
+
483
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/traffic%20light%20quick%20start%20tutorial/Off%20To%20From%20RGY.png)
484
+
485
+
486
+
487
+ <br/>
488
+
489
+ ### Let's actually use the traffic light
490
+
491
+ That's actually the bulk of the language. There are other little add-ons here and there, but, primarily you now know
492
+ how to write a state machine.
493
+
494
+ Let's load it and use it! 😀
495
+
496
+ #### loading into node
497
+ #### loading into html
498
+ #### jssm-viz
499
+ #### redistribution on npm
500
+
501
+
502
+
503
+ <br/>
504
+
505
+ ### An introduction to machine design
506
+
507
+ Let's make a `state machine` for ATMs. In the process, we will use a lot of core concepts of `finite state machine`s
508
+ and of `jssm-dot`, this library's `DSL`.
509
+
510
+ We're going to improve on this [NCSU ATM diagram](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif) that I
511
+ found:
512
+
513
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/ncsu%20atm%20diagram.gif)
514
+
515
+ Remember, at any time, you can take the code and put it into the
516
+ [graph explorer](https://stonecypher.github.io/jssm-viz-demo/graph_explorer.html) for an opportunity to mess with the
517
+ code as you see fit.
518
+
519
+
520
+
521
+ <br/>
522
+
523
+ #### 0: Empty machine
524
+
525
+ We'll start with an [empty machine](https://github.com/StoneCypher/jssm/blob/master/src/machines/atm%20quick%20start%20tutorial/1_EmptyWaiting.jssm).
526
+
527
+ ```fsl
528
+ EmptyWaiting 'Wait' -> EmptyWaiting;
529
+ ```
530
+
531
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/0_EmptyWaiting.png)
532
+
533
+
534
+
535
+ <br/>
536
+
537
+ #### 1: Should be able to eject cards
538
+
539
+ We'll add the ability to physically eject the user's card and reset to the empty and waiting state. Right now it'll
540
+ dangle around un-used at the top, but later it'll become useful.
541
+
542
+ This is expressed as the path `EjectCardAndReset -> EmptyWaiting;`
543
+
544
+ ```fsl
545
+ EmptyWaiting 'Wait' -> EmptyWaiting;
546
+ EjectCardAndReset -> EmptyWaiting;
547
+ ```
548
+
549
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/1_EjectCard.png)
550
+
551
+
552
+
553
+ <br/>
554
+
555
+ #### 2: Should be able to insert cards
556
+
557
+ We'll add the ability to physically insert a card, next. You know, the, uh, thing ATMs are pretty much for.
558
+
559
+ To get this, add the path leg `EmptyWaiting 'InsertCard' -> HasCardNoAuth;`
560
+
561
+ ```fsl
562
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
563
+ EjectCardAndReset -> EmptyWaiting;
564
+ ```
565
+
566
+ Notice that the new `state`, **HasCardNoAuth**, has been rendered red. This is because it is `terminal` - there is
567
+ no exit from this node currently. (**EmptyAndWaiting** did not render that way because it had a transition to itself.)
568
+ That will change as we go back to adding more nodes. `terminal node`s are usually either mistakes or the last single
569
+ `state` of a given `FSM`.
570
+
571
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/2_InsertCard.png)
572
+
573
+
574
+
575
+ <br/>
576
+
577
+ #### 3: Should be able to cancel and recover the card
578
+
579
+ Next, we should have a cancel, because the ATM's <key>7</key> key is broken, and we need our card back. Cancel will
580
+ exit to the main menu, and return our card credential.
581
+
582
+ To that end, we add the path `HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;`
583
+
584
+ ```fsl
585
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
586
+
587
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
588
+
589
+ EjectCardAndReset -> EmptyWaiting;
590
+ ```
591
+
592
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/3_ReturnCard.png)
593
+
594
+
595
+
596
+ <br/>
597
+
598
+ #### 4: Can give the wrong PIN
599
+
600
+ Next, let's give the ability to get the password ... wrong. 😂 Because we all know that one ATM that only has the
601
+ wrong-PIN path, so, apparently that's a product to someone.
602
+
603
+ When they get the PIN wrong, they're prompted to try again (or to cancel.)
604
+
605
+ We'll add the path `HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;`
606
+
607
+ ```fsl
608
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
609
+
610
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
611
+ HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
612
+
613
+ EjectCardAndReset -> EmptyWaiting;
614
+ ```
615
+
616
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/4_WrongPin.png)
617
+
618
+
619
+
620
+
621
+
622
+ <br/>
623
+
624
+ #### 5: Can give the correct PIN
625
+
626
+ Next, let's give the ability to get the password right.
627
+
628
+ We'll add two paths. The first gets the password right: `HasCardNoAuth 'RightPIN' -> MainMenu;`
629
+
630
+ The second, from our new `state` **MainMenu**, gives people the ability to leave: `MainMenu 'ExitReturnCard' -> EjectCardAndReset;`
631
+
632
+
633
+ ```fsl
634
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
635
+
636
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
637
+ HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
638
+ HasCardNoAuth 'RightPIN' -> MainMenu;
639
+
640
+ MainMenu 'ExitReturnCard' -> EjectCardAndReset;
641
+
642
+ EjectCardAndReset -> EmptyWaiting;
643
+ ```
644
+
645
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/5_RightPin.png)
646
+
647
+
648
+
649
+ <br/>
650
+
651
+ #### 6: Can check balance from main menu
652
+
653
+ Hooray, now we're getting somewhere.
654
+
655
+ Let's add the ability to check your balance. First pick that from the main menu, then pick which account to see the
656
+ balance of, then you're shown a screen with the information you requested; then go back to the main menu.
657
+
658
+ That's `MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;`.
659
+
660
+ ```fsl
661
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
662
+
663
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
664
+ HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
665
+ HasCardNoAuth 'RightPIN' -> MainMenu;
666
+
667
+ MainMenu 'ExitReturnCard' -> EjectCardAndReset;
668
+ MainMenu 'CheckBalance' -> PickAccount -> DisplayBalance -> MainMenu;
669
+
670
+ EjectCardAndReset -> EmptyWaiting;
671
+ ```
672
+
673
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/6_CanCheckBalance.png)
674
+
675
+
676
+
677
+ <br/>
678
+
679
+ #### 7: Can deposit money from main menu
680
+
681
+ Let's add something difficult. Their state machine just proceeds assuming everything is okay.
682
+
683
+ To desposit money:
684
+
685
+ 1. Accept physical money
686
+ 2. If accept failed (eg door jammed,) reject physical object, go to main menu
687
+ 3. If accept succeeded, ask human expected value
688
+ 4. Pick an account this should go into
689
+ 5. Contact bank. Request to credit for theoretical physical money.
690
+ 6. Three results: yes, no, offer-after-audit.
691
+ 7. If no, reject physical object, go to main menu.
692
+ 8. If yes, consume physical object, tell user consumed, go to main menu
693
+ 9. If offer-after-audit, ask human what to do
694
+ 10. if human-yes, consume physical object, tell user consumed, go to main menu
695
+ 11. if human-no, reject physical object, go to main menu
696
+
697
+ Writing this out in code is not only generally longer than the text form, but also error prone and hard to maintain.
698
+
699
+ ... or there's the `FSM` `DSL`, which is usually as-brief-as the text, and frequently both briefer and more explicit.
700
+
701
+ * Rules 1-2: `MainMenu 'AcceptDeposit' -> TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;`
702
+ * Rules 3-6: `TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;`
703
+ * Rule 7: `BankResponse 'BankNo' -> RejectPhysicalMoney;`
704
+ * Rule 8: `BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;`
705
+ * Rules 9-10: `BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;`
706
+ * Rule 11: `BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;`
707
+
708
+ Or, as a block,
709
+
710
+ ```fsl
711
+ MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
712
+
713
+ TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
714
+ TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
715
+
716
+ BankResponse 'BankNo' -> RejectPhysicalMoney;
717
+ BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
718
+ BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
719
+
720
+ BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
721
+ ```
722
+
723
+ Which leaves us with the total code
724
+
725
+
726
+ ```fsl
727
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
728
+
729
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
730
+ HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
731
+ HasCardNoAuth 'RightPIN' -> MainMenu;
732
+
733
+ MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
734
+ MainMenu 'ExitReturnCard' -> EjectCardAndReset;
735
+ MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
736
+
737
+ TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
738
+ TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
739
+
740
+ BankResponse 'BankNo' -> RejectPhysicalMoney;
741
+ BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
742
+ BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
743
+
744
+ BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
745
+
746
+ EjectCardAndReset -> EmptyWaiting;
747
+ ```
748
+
749
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/7_CanDepositMoney.png)
750
+
751
+
752
+
753
+ <br/>
754
+
755
+ #### 8: Can withdraw money from main menu
756
+
757
+ Let's also be able to take money from the machine. After this, we'll move on, since our example is pretty squarely made
758
+ by now.
759
+
760
+ 1. Pick a withdrawl account, or cancel to the main menu
761
+ 2. Shown a balance, pick a withdrawl amount, or cancel to acct picker
762
+ 3. Is the withdrawl account too high? If so go to 2
763
+ 4. Does the machine actually have the money? If not go to 2
764
+ 5. Otherwise confirm intent w/ human
765
+ 6. Attempt to post the transaction.
766
+ 7. If fail, display reason and go to 1
767
+ 8. If succeed, dispense money and go to main menu
768
+
769
+ * Rules 1-3: `MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;`
770
+ * Rule 4: `AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;`
771
+ * Rule 5: `MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;`
772
+ * Rule 6: `ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;`
773
+ * Rule 7: `BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;`
774
+ * Rule 8: `BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;`
775
+
776
+ Rule 1 canceller: `PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;`
777
+ Rule 2 canceller: `PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;`
778
+
779
+ Or as a whole, we're adding
780
+
781
+ ```fsl
782
+ MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
783
+ AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
784
+ MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
785
+ ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
786
+ BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
787
+ BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
788
+
789
+ PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
790
+ PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
791
+ ```
792
+
793
+ Which leaves us with
794
+
795
+ ```fsl
796
+ EmptyWaiting 'Wait' -> EmptyWaiting 'InsertCard' -> HasCardNoAuth;
797
+
798
+ HasCardNoAuth 'CancelAuthReturnCard' -> EjectCardAndReset;
799
+ HasCardNoAuth 'WrongPIN' -> HasCardNoAuth;
800
+ HasCardNoAuth 'RightPIN' -> MainMenu;
801
+
802
+ MainMenu 'AcceptDeposit' -> TentativeAcceptMoney;
803
+ MainMenu 'ExitReturnCard' -> EjectCardAndReset;
804
+ MainMenu 'CheckBalance' -> PickCheckBalanceAccount -> DisplayBalance -> MainMenu;
805
+
806
+ TentativeAcceptMoney 'AcceptFail' -> RejectPhysicalMoney -> MainMenu;
807
+ TentativeAcceptMoney 'AcceptSucceed' -> PickDepositAccount -> RequestValue 'TellBank' -> BankResponse;
808
+
809
+ BankResponse 'BankNo' -> RejectPhysicalMoney;
810
+ BankResponse 'BankYes' -> ConsumeMoney -> NotifyConsumed -> MainMenu;
811
+ BankResponse 'BankAudit' -> BankAuditOffer 'HumanAcceptAudit' -> ConsumeMoney;
812
+
813
+ BankAuditOffer 'HumanRejectAudit' -> RejectPhysicalMoney;
814
+
815
+ MainMenu -> PickWithdrawlAccount -> PickAmount -> AcctHasMoney? 'TooHighForAcct' -> PickWithdrawlAccount;
816
+ AcctHasMoney? -> MachineHasMoney? 'MachineLowOnCash' -> PickAmount;
817
+ MachineHasMoney? -> ConfirmWithdrawWithHuman 'MakeChanges' -> PickWithdrawlAmount;
818
+ ConfirmWithdrawWithHuman 'PostWithdrawl' -> BankWithdrawlResponse;
819
+ BankWithdrawlResponse 'WithdrawlFailure' -> WithdrawlFailureExplanation -> PickWithdrawlAccount;
820
+ BankWithdrawlResponse 'WithdrawlSuccess' -> DispenseMoney -> MainMenu;
821
+
822
+ PickWithdrawlAccount 'CancelWithdrawl' -> MainMenu;
823
+ PickWithdrawlAmount 'SwitchAccounts' -> PickWithdrawlAccount;
824
+
825
+ EjectCardAndReset -> EmptyWaiting;
826
+ ```
827
+
828
+ ![](https://raw.githubusercontent.com/StoneCypher/jssm/master/src/assets/atm%20quick%20start%20tutorial/8_CanWithdrawMoney.png)
829
+
830
+ As you can see, building up even very complex state machines is actually relatively straightforward, in a short
831
+ amount of time.
832
+
833
+
834
+
835
+ <br/><br/>
836
+
837
+ ## Features
838
+ ### DSL
839
+ ### States
840
+ ### Transitions
841
+ ### Cycles
842
+ ### Stripes
843
+ ### Named Ordered Lists
844
+ ### Atoms
845
+ ### Strings
846
+ ### Arrow types
847
+ ### Unicode representations
848
+ ### Node declarations
849
+ ### All the styling bullshit
850
+ ### Named edges
851
+ ### URL callouts
852
+ ### The 9 or whatever directives
853
+ ### How to publish a machine
854
+ #### Legal, main, and forced
855
+ ### Validators
856
+ ### State history
857
+ ### Automatic visualization
858
+
859
+
860
+
861
+ <br/><br/>
862
+
863
+ ## How to think in state machines
864
+
865
+
866
+
867
+ <br/><br/>
868
+
869
+ ## Example Machines
870
+ ### Door lock
871
+ ### Traffic lights
872
+ #### Basic three-state
873
+ #### RYG, Off, Flash-red, Flash-yellow
874
+ #### RYG, Off, Flash-red, Flash-yellow, Green-left, Yellow-left
875
+ #### Heirarchal intersection
876
+ ### [ATM](https://people.engr.ncsu.edu/efg/210/s99/Notes/fsm/atm.gif)
877
+ ### [HTTP](https://www.w3.org/Library/User/Architecture/HTTP.gif)
878
+ #### Better HTTP
879
+ ### [TCP](http://www.texample.net/media/tikz/examples/PNG/tcp-state-machine.png)
880
+ ### Coin-op vending machine (data)
881
+ ### Video games
882
+ #### Pac-man Ghost (sensors)
883
+ #### Weather (probabilistics)
884
+ #### Roguelike monster (interface satisfaction)
885
+ ### Candy crush clone game flow (practical large use)
886
+ ### Vegas locked 21 dealer behavior
887
+ ### React SPA website (practical large use)
888
+ ### [BGP](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/BGP_FSM.svg/549px-BGP_FSM.svg.png)
889
+ ### [LibGCrypt FIPS mode FSM](https://www.gnupg.org/documentation/manuals/gcrypt/fips-fsm.png)
890
+
891
+
892
+
893
+ <br/><br/>
894
+
895
+ ## How to debug
896
+
897
+
898
+
899
+ <br/><br/>
900
+
901
+ ## How to publish
902
+ It's really quite simple.
903
+
904
+ 1. Make a github repository.
905
+ 1. Put your code in a file inside, with the extension `.fsl`
906
+ 1. Make sure your code contains a `machine_name`
907
+
908
+ Once done, your work should show up [here](https://github.com/search?utf8=%E2%9C%93&q=extension%3Afsl+machine_name&type=Code).
909
+
910
+
911
+
912
+ <br/><br/>
913
+
914
+ ## Notation Comparison
915
+ ### Their notations, one by one
916
+ ### Apples to Apples - Traffic Light
917
+
918
+
919
+
920
+ <br/><br/>
921
+
922
+ ## Other state machines
923
+ There are a lot of state machine impls for JS, many quite a bit more mature than this one. Here are some options:
924
+
925
+ 1. [Finity](https://github.com/nickuraltsev/finity) 😮
926
+ 1. [Stately.js](https://github.com/fschaefer/Stately.js)
927
+ 1. [machina.js](https://github.com/ifandelse/machina.js)
928
+ 1. [Pastafarian](https://github.com/orbitbot/pastafarian)
929
+ 1. [Henderson](https://github.com/orbitbot/henderson)
930
+ 1. [fsm-as-promised](https://github.com/vstirbu/fsm-as-promised)
931
+ 1. [state-machine](https://github.com/DEADB17/state-machine)
932
+ 1. [mood](https://github.com/bredele/mood)
933
+ 1. [FSM Workbench](https://github.com/MatthewHepburn/FSM-Workbench)
934
+ 1. [SimpleStateMachine](https://github.com/ccnokes/SimpleStateMachine)
935
+ 1. shime/[micro-machine](https://github.com/shime/micro-machine)
936
+ 1. soveran/[micromachine](https://github.com/soveran/micromachine) (ruby)
937
+ 1. fabiospampinato/[FSM](https://github.com/fabiospampinato/FSM)
938
+ 1. HQarroum/[FSM](https://github.com/HQarroum/Fsm)
939
+ 1. [Finite-State-Automata](https://github.com/RolandR/Finite-State-Automata)
940
+ 1. [finite-state-machine](https://github.com/MarkH817/finite-state-machine)
941
+ 1. [nfm](https://github.com/ajauhri/nfm)
942
+
943
+
944
+ And some similar stuff:
945
+ 1. [redux-machine](https://github.com/mheiber/redux-machine)
946
+ 1. [ember-fsm](https://github.com/heycarsten/ember-fsm)
947
+ 1. [State machine cat](https://github.com/sverweij/state-machine-cat)
948
+ 1. [Workty](https://github.com/AlexLevshin/workty) 😮
949
+ 1. [sam-simpler](https://github.com/sladiri/sam-simpler)
950
+ 1. [event_chain](https://github.com/quilin/event_chain)
951
+ 1. [DRAKON](https://en.wikipedia.org/wiki/DRAKON)
952
+ 1. [Yakindu Statechart Tools](https://github.com/Yakindu/statecharts)
953
+ 1. [GraphViz](http://www.graphviz.org/)
954
+ 1. [Viz.js](https://github.com/mdaines/viz.js/), which we use
955
+
956
+
957
+
958
+ <br/><br/><br/>
959
+
960
+ # Thanks
961
+
962
+ JSSM and FSL have had a lot of help.
963
+
964
+
965
+
966
+ <br/><br/>
967
+
968
+ ## Internationalization
969
+
970
+ * [Mykhaylo Les](https://github.com/miles91) provided three translation test cases ([Ukrainian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/ukrainian.json), [Belarussian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/belarussian.json), and [Russian](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/russian.json),) and the corresponding Traffic Light translations (also [Ukrainian](https://github.com/StoneCypher/fsl_traffic_light_ukrainian/blob/master/traffic%20light.fsl), [Belarussian](https://github.com/StoneCypher/fsl_traffic_light_belarussian/blob/master/traffic_light.fsl), and [Russian](https://github.com/StoneCypher/fsl_traffic_light_russian/blob/master/traffic%20light.fsl).)
971
+ * [Tanvir Islam](https://github.com/tanvirrb) provided the [Bengali test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/bengali.json), translated the [Traffic Light](https://github.com/tanvirrb/fsl-traffic-light-bengali/blob/master/traffic_light.fsl) to Bengali, and published the first non-English `FSL` machine, in Bengali.
972
+ * [Francisco Junior](https://github.com/fcojr) provided the [Portuguese test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/portuguese.json) and translated the [Traffic Light](https://github.com/StoneCypher/fsl_traffic_light_portuguese/blob/master/traffic_light.fsl) to Portuguese
973
+ * [Jeff Katz](https://github.com/kraln) provided the [German test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/german.json).
974
+ * [Alex Cresswell](https://github.com/technophile77) provdied the [Spanish test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/spanish.json)
975
+ * [Dvir Cohen](https://github.com/cohendvir) provided the [Hebrew test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/hebrew.json).
976
+ * [David de la Peña](https://github.com/daviddelapena) provided the [French test case](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/french.json)
977
+
978
+ If I've overlooked you, please let me know.
979
+
980
+ If you'd like to help, it's straightforward.
981
+
982
+ 1. Easy mode: open a PR with [this file](https://github.com/StoneCypher/jssm/blob/master/src/js/tests/language_data/english.json) translated into your language
983
+ 1. Extra mile: create a new repo containing [this file](https://github.com/StoneCypher/fsl_traffic_light/blob/master/traffic_light.fsl) translated
984
+
985
+
986
+
987
+ <br/><br/>
988
+
989
+ ## Code and Language
990
+
991
+ [Forest Belton](https://github.com/forestbelton) has provided guidance, bugfixes, parser and language commentary.
992
+
993
+ [Jordan Harbrand](https://github.com/ljharb) suggested two interesting features and provided strong feedback on the initial tutorial draft.
994
+
995
+ The biggest thanks must go to [Michael Morgan](https://github.com/msmorgan/), who has debated significant sections of
996
+ the notation, invented several concepts and operators, helped with the parser, with system nomenclature, for having published
997
+ the first not-by-me `FSL` machine, for encouragement, and generally just for having been as interested as he has been.