jssm 5.39.0 → 5.43.2

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