diff --git a/doc/_static/state_recipe_15.pdf b/doc/_static/state_recipe_15.pdf
index 9d18e50..ba97d85 100644
Binary files a/doc/_static/state_recipe_15.pdf and b/doc/_static/state_recipe_15.pdf differ
diff --git a/doc/_static/state_recipe_15.svg b/doc/_static/state_recipe_15.svg
index f098a2c..a5e01f0 100644
--- a/doc/_static/state_recipe_15.svg
+++ b/doc/_static/state_recipe_15.svg
@@ -1,7 +1,7 @@
-
UMLState
- 150
- 260
+ 170
+ 450810450
@@ -31,8 +31,8 @@ valign=top
UMLState
- 550
- 500
+ 570
+ 690350160
@@ -54,8 +54,8 @@ valign=top
UMLClass
- 100
- 120
+ 120
+ 310890660
@@ -63,7 +63,7 @@ valign=top
--
live_spy
live_trace
-times_in_inner # property wrapping deque derived object
+times_in_inner # thread safe attribute
--
trace_callback(self, trace)
spy_callback(self, spy)
@@ -74,8 +74,8 @@ layer=0
UMLSpecialState
- 180
- 530
+ 200
+ 7202020
@@ -86,8 +86,8 @@ layer=3
Relation
- 190
- 520
+ 210
+ 71031040
@@ -99,8 +99,8 @@ layer=3
Relation
- 270
- 700
+ 290
+ 89054060
@@ -111,8 +111,8 @@ layer=3
Text
- 350
- 720
+ 370
+ 91038030
@@ -124,8 +124,8 @@ layer=3
UMLClass
- 110
- 0
+ 130
+ 19010030
@@ -135,8 +135,8 @@ layer=3
Relation
- 150
- 80
+ 170
+ 2703060
@@ -147,8 +147,8 @@ layer=3
Relation
- 270
- 80
+ 540
+ 2703060
@@ -158,8 +158,8 @@ layer=3
UMLClass
- 230
- 60
+ 500
+ 25010030
@@ -169,8 +169,8 @@ layer=3
UMLClass
- 110
- 60
+ 130
+ 25010030
@@ -180,8 +180,8 @@ layer=3
Relation
- 150
- 20
+ 170
+ 2103060
@@ -192,8 +192,8 @@ layer=3
Text
- 530
- 30
+ 740
+ 22027070
@@ -208,8 +208,8 @@ layer=3
UMLUseCase
- 130
- 370
+ 150
+ 5602020
@@ -221,8 +221,8 @@ layer=3
UMLUseCase
- 130
- 400
+ 150
+ 5902020
@@ -234,8 +234,8 @@ layer=3
UMLClass
- 100
- 810
+ 120
+ 1000430220
@@ -248,8 +248,8 @@ layer=0
UMLState
- 160
- 870
+ 180
+ 1060310120
@@ -268,8 +268,8 @@ valign=top
UMLState
- 130
- 850
+ 150
+ 1040370160
@@ -281,8 +281,8 @@ layer=0
Relation
- 290
- 770
+ 310
+ 9603060
@@ -293,8 +293,8 @@ layer=3
UMLState
- 480
- 300
+ 500
+ 490440380
@@ -318,8 +318,8 @@ valign=top
Relation
- 470
- 570
+ 490
+ 76010040
@@ -331,8 +331,8 @@ layer=3
UMLNote
- 770
- 380
+ 790
+ 57014070
@@ -346,8 +346,8 @@ layer=3
Relation
- 690
- 420
+ 710
+ 61010060
@@ -358,8 +358,8 @@ layer=3
UMLClass
- 350
- 60
+ 620
+ 25010030
@@ -369,12 +369,35 @@ layer=3
Relation
- 390
- 80
+ 660
+ 2703060lt=<<<<<-10.0;40.0;10.0;10.0
+
+ Relation
+
+ 310
+ 270
+ 30
+ 60
+
+ lt=<<-
+layer=3
+ 10.0;10.0;10.0;40.0
+
+
+ UMLClass
+
+ 250
+ 250
+ 150
+ 30
+
+ ThreadSafeAttributes
+
+
diff --git a/doc/i_thread_safe_attributes.rst b/doc/i_thread_safe_attributes.rst
index 14aceb1..55017bf 100644
--- a/doc/i_thread_safe_attributes.rst
+++ b/doc/i_thread_safe_attributes.rst
@@ -1,66 +1,66 @@
-.. included from recipes
-
-Anytime you start a statechart, your program is multi-threaded. Sometimes, you
-will want to access an attribute of your statechart from another thread,
-like the main part of your program. When you do this, you are trying to
-access memory that could be changed in one thread while it is being read in by
-another thread.
-
-To see why this is an issue imagine using a calculator to solve a simple math
-problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
-following equation:
-
-.. code-block:: python
-
- b = a*cos(0.45) + 3*a^1.2
-
-Seems simple enough. You pick a straight-forward strategy:
-
- * mark down the value of ``a`` on a piece of paper so you can reference it as you work
- * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
- * then add these results together to find ``b``
-
-But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
-paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
-your desk. You don't notice. When you get to the ``3*a^1.2`` part of the
-calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
-
-This is called a **race condition**. Here our ``a`` variable was shared between
-two threads, you and the other person. When you program with multiple
-concurrent processes/threads and you share memory, you are exposed to this kind
-of problem.
-
-A simple way to avoid such a situation is to not share the temporary paper in
-the first place. Do not use shared attributes.
-
-Another way to deal with it is to have one thread change a shared attribute and
-have the other thread read the shared attribute. But, this will required that
-maintenance developers understand there are hidden rules in your code base;
-they could innocently change something an introduce extremely subtle bugs.
-
-Typically, shared variables are protected using thread locks. A lock is a flag
-which works across multiple threads. You can lock the object for read/writing
-while you use it. In our example, we would lock ``a`` in its ``0.35`` state
-while calculating both sub-parts of our problem then unlock it when we are done.
-The other process, would simply wait until the thread-lock cleared, then they
-would change the value of ``a`` to ``0.3`` and do their own work. So, there is
-a cost, you block one thread while waiting for the other to work, and you have
-to share lock variables across all of your threads. It is easy to screw this
-up, and it is very hard to test for race conditions.
-
-But why is it hard to test for race conditions? As of Python 3, a thread will
-run for 15 milliseconds before Python passes control to another thread. Most of
-the time, the common memory that is used by both threads will work as you expect
-it to. Infrequently a thread switch will occur midway through a non-atomic
-operation, where some shared value happen to also be changed by the other
-thread. When the Python task manager switches back to your thread, the result
-of your calculation will be wrong. These kinds of bugs are more probabilistic
-than deterministic, because Python's access to the system clock is jittery: It's
-timing will never be the same every two runs of the program, so it will be hard
-for you to reproduce your issue.
-
-The miros library accepts that people will want to access a statechart's internal
-attributes from the outside. Significant efforts have been made to make this
-kind of activity easy for you to do in a "thread-safe" manner. The
-``ThreadSafeAttributes`` class was constructed to make this easy for you.
-
+.. included from recipes
+
+Anytime you start a statechart, your program is multi-threaded. Sometimes, you
+will want to access an attribute of your statechart from another thread,
+like the main part of your program. When you do this, you are trying to
+access memory that could be changed in one thread while it is being read in by
+another thread.
+
+To see why this is an issue imagine using a calculator to solve a simple math
+problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
+following equation:
+
+.. code-block:: python
+
+ b = a*cos(0.45) + 3*a^1.2
+
+Seems simple enough. You pick a straight-forward strategy:
+
+ * mark down the value of ``a`` on a piece of paper so you can reference it as you work
+ * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
+ * then add these results together to find ``b``
+
+But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
+paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
+your desk. You don't notice. When you get to the ``3*a^1.2`` part of the
+calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
+
+This is called a **race condition**. Here our ``a`` variable was shared between
+two threads, you and the other person. When you program with multiple
+concurrent processes/threads and you share memory, you are exposed to this kind
+of problem.
+
+A simple way to avoid such a situation is to not share the temporary paper in
+the first place. Do not use shared attributes.
+
+Another way to deal with it is to have one thread change a shared attribute and
+have the other thread read the shared attribute. But, this will required that
+maintenance developers understand there are hidden rules in your code base;
+they could innocently change something an introduce extremely subtle bugs.
+
+Typically, shared variables are protected using thread locks. A lock is a flag
+which works across multiple threads. You can lock the object for read/writing
+while you use it. In our example, we would lock ``a`` in its ``0.35`` state
+while calculating both sub-parts of our problem then unlock it when we are done.
+The other process, would simply wait until the thread-lock cleared, then they
+would change the value of ``a`` to ``0.3`` and do their own work. So, there is
+a cost, you block one thread while waiting for the other to work, and you have
+to share lock variables across all of your threads. It is easy to screw this
+up, and it is very hard to test for race conditions.
+
+But why is it hard to test for race conditions? As of Python 3, a thread will
+run for 15 milliseconds before Python passes control to another thread. Most of
+the time, the common memory that is used by both threads will work as you expect
+it to. Infrequently a thread switch will occur midway through a non-atomic
+operation, where some shared value happen to also be changed by the other
+thread. When the Python task manager switches back to your thread, the result
+of your calculation will be wrong. These kinds of bugs are more probabilistic
+than deterministic, because Python's access to the system clock is jittery: It's
+timing will never be the same every two runs of the program, so it will be hard
+for you to reproduce your issue.
+
+The miros library accepts that people will want to access a statechart's internal
+attributes from the outside. Significant efforts have been made to make this
+kind of activity easy for you to do in a "thread-safe" manner. The
+``ThreadSafeAttributes`` class was constructed to make this easy for you.
+
diff --git a/doc/introduction.rst b/doc/introduction.rst
index c2591d6..bd09d0c 100644
--- a/doc/introduction.rst
+++ b/doc/introduction.rst
@@ -261,8 +261,8 @@ about it.
Python has advanced significantly since the 90s. UML cannot capture all of the
expressive power of the language, but it doesn't have to; if you don't know how
-to draw your intention (list comprehensions, generators, properties, etc.), you
-can just write the code onto your diagram.
+to draw your intention (super, list comprehensions, generators, properties,
+etc.), you can just write the code onto your diagram.
.. _introduction-what-this-documentation-will-provide:
diff --git a/doc/reading_diagrams.rst b/doc/reading_diagrams.rst
index 79970cd..30a303e 100644
--- a/doc/reading_diagrams.rst
+++ b/doc/reading_diagrams.rst
@@ -29,7 +29,7 @@ form.
To make a picture language, or any programming language is complicated, so as
the rules governing the picture language became more complex, it became less
-useful for those who just wanted to use it to share ideas.
+useful for software practitioners.
.. note::
@@ -60,30 +60,29 @@ Martin Fowler rendered down the complexity of the UML standard into: `UML
distilled `_. If you want a very solid
understanding about Harel formalism as it relates to UML, go to the source and
read `Practical UML Statecharts in C/C++, 2nd Edition
-`_ by Miro
-Samek.
+`_ by Dr.
+Miro Samek.
But do you need to read these books before you use UML? No, because we are not
going to treat UML as a formal computer language with mathematical semantics. We
will use UML as something to sketch with.
+The formal language we will use is Python.
+
+This section should give you enough information so that you can make your own
+pictures.
+
*Software modelers depend on and use engineering analogies but often fail to
- understand them. Engineers realize that the models aren't the product; they're
- abstractions of the product. In fact, in most cases, the models are only
- partial abstractions of the product, used to hightlight aspects that the
- engineer should know about the product. The term
- 'executable specification' is an oxymoron -- if the specification were truly executable, it would
+ understand them. Engineers realize that the models aren't the product;
+ they're abstractions of the product. In fact, in most cases, the models are
+ only partial abstractions of the product, used to highlight aspects that the
+ engineer should know about the product. The term 'executable specification'
+ is an oxymoron -- if the specification were truly executable, it would
actually be "the thing". Otherwise, it would merely model "the thing," which
by definition is partial and incomplete.*
-- Dave Thomas
-
-The formal language we will use is Python.
-
-This section should give you enough information so that you can make your own
-pictures.
-
.. _reading_diagrams-install-drawing-software:
Install drawing software
@@ -99,7 +98,7 @@ If you don't have a UML drawing package, go and get one.
Install `UMLet `_.
If you would like to use my pallets, remove the ``palettes`` folder from the
- ``UMLet`` directory, then naviage to that directory in your shell and type:
+ ``UMLet`` directory, then navigate to that directory in your shell and type:
.. code-block:: bash
@@ -113,6 +112,8 @@ The Most Important Rule in UML
**You don't have to draw everything on your picture.**
+Sometimes less is more.
+
.. _reading_diagrams-classes:
Classes
@@ -236,6 +237,13 @@ If you are going to inherit ask yourself if the "is-a", or "is-an", relationship
holds true when you use the two class names in a sentence. "The ToasterOven
class is an ActiveObject"; yes, that makes sense. Ok, I'll use inheritance.
+.. note::
+
+ Technically speaking, you `can't draw static inheritance
+ diagrams`_ when you use Python.
+ It is the child class that determines what ``super`` means, because the MRO
+ is determined dynamically using a process called linearization.
+
If you want all of the states of your statechart to react the same when they see
a specific event, use the :ref:`ultimate hook pattern `.
This gives you all of the benefits of inheritance while still having debuggable
diff --git a/doc/recipes.rst b/doc/recipes.rst
index 4dc329b..3a5fae3 100644
--- a/doc/recipes.rst
+++ b/doc/recipes.rst
@@ -22,7 +22,9 @@ Demonstration of Capabilities
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this section I'll show you how you can use the miros library by layering more
-and more of its features into a simple program.
+and more of its features into a simple program. This program will be arbitrary,
+it serves no purpose other than to show how to do the common things you will
+want to do when you build your own systems.
.. contents::
:local:
@@ -57,7 +59,7 @@ interplay is a Hierarchical State Machine (HSM) behavior which follows the Harel
Formalism (picture-to-behavior rules).
Now that we understand a bit of theory and how the miros abstraction works,
-let's look at some examples.
+let's write some code.
.. _recipes-minimal-viable-states:
@@ -2291,340 +2293,313 @@ inner_state about 1 second after the middle_state was entered.
Creating thread-safe class Attributes
-------------------------------------
+If you build a statechart using miros your program is multithreaded. This means
+that if you would like to access the same variable across two threads, you need
+to lock it so that one thread doesn't write to it while another thread is using
+it.
-..
- Creating thread-safe class Attributes
- -------------------------------------
- A statechart is running in a separate thread from our main program; so how do we
- reach into it and read/write a variable? We can't assume that it's thread
- won't be halfway through changing the variable we want to read/write at the moment we
- are trying to access it.
-
- To solve this problem we can use a thread safe queue. If we use the
- ``collections.deque`` from the Python standard library, we can build a little ring
- buffer. The statechart can post information to it, and the main thread can
- read information from it. If we wrap the deque in a ``@property``, our exposed
- variable will just look like an attribute from outside of the class.
-
- Here is an example design of where we turn the ``times_in_inner`` attribute into a
- thread-safe property.
-
- .. image:: _static/state_recipe_15.svg
- :target: _static/state_recipe_15.pdf
- :align: center
-
- There is no UML drawing syntax for creating a Python property, so I just add a
- comment on the diagram after the ``times_in_inner`` attribute about what it
- really is.
+Here is an example design of where we turn the ``times_in_inner`` attribute into a
+thread-safe property using the ``ThreadSafeAttributes`` class (available in
+miros >= 4.1.3).
- We can see how to make the ``times_in_inner`` thread safe attribute below (see
- the highlighted code):
-
- .. code-block:: python
- :emphasize-lines: 25-27, 81-83, 85-87, 153, 209, 210
+.. image:: _static/state_recipe_15.svg
+ :target: _static/state_recipe_15.pdf
+ :align: center
+
+.. note::
+
+ There is no UML drawing syntax for describing an attribute wrapped by a
+ property. There is no UML diagram to show a thread lock, or how multiple
+ inheritance works through `linearization of parent classes
+ `_ using Python ``super()``.
+ Our UML is just a sketch, so we make a note that the ``times_in_inner``
+ is a thread safe attribute and move on.
+
+The ``ThreadSafeAttributes`` class tries to protect you from race conditions by
+inspecting the line of code where the ``times_in_inner`` variable is used and
+wrap it within a thread lock. The ``ThreadSafeAttributes`` is :ref:`limited in
+it's capabilities `, but it will
+lock the non-atomic ``+=`` operation seen below:
+
+.. code-block:: python
+ :emphasize-lines: 11, 15, 143, 199, 200
- # simple_state_15.py
- import re
- import time
- import logging
- from functools import partial
- from collections import deque
-
- from miros import Event
- from miros import signals
- from miros import Factory
- from miros import return_status
-
- class F1(Factory):
-
- def __init__(self, name, log_file_name=None,
- live_trace=None, live_spy=None):
-
- super().__init__(name)
-
- self.live_trace = \
- False if live_trace == None else live_trace
- self.live_spy = \
- False if live_spy == None else live_spy
-
- # set up a thread safe ring buffer of size 1
- self._times_in_inner = deque(maxlen=1)
- self._times_in_inner.append(0)
-
- self.log_file_name = \
- 'simple_state_15.log' if log_file_name == None else log_file_name
-
- # clear our log every time we run this program
- with open(self.log_file_name, "w") as fp:
- fp.write("")
-
- logging.basicConfig(
- format='%(asctime)s %(levelname)s:%(message)s',
- filename=self.log_file_name,
- level=logging.DEBUG)
-
- self.register_live_spy_callback(partial(self.spy_callback))
- self.register_live_trace_callback(partial(self.trace_callback))
-
- self.outer_state = self.create(state="outer_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.outer_state_entry_signal). \
- catch(signal=signals.INIT_SIGNAL,
- handler=self.outer_state_init_signal). \
- catch(signal=signals.Hook,
- handler=self.outer_state_hook). \
- catch(signal=signals.Send_Broadcast, \
- handler=self.outer_state_send_broadcast). \
- catch(signal=signals.BROADCAST, \
- handler=self.outer_state_broadcast). \
- catch(signal=signals.Reset,
- handler=self.outer_state_reset). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.outer_state_exit_signal). \
- to_method()
-
- self.middle_state = self.create(state="middle_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.middle_state_entry_signal). \
- catch(signal=signals.Ready,
- handler=self.middle_state_ready). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.middle_state_exit_signal). \
- to_method()
-
- self.inner_state = self.create(state="inner_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.inner_state_entry_signal). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.inner_state_exit_signal). \
- to_method()
-
- self.nest(self.outer_state, parent=None). \
- nest(self.middle_state, parent=self.outer_state). \
- nest(self.inner_state, parent=self.middle_state)
-
- @property
- def times_in_inner(self):
- return self._times_in_inner[-1]
-
- @times_in_inner.setter
- def times_in_inner(self, value):
- self._times_in_inner.append(value)
-
- def trace_callback(self, trace):
- '''trace without datetime-stamp'''
- trace_without_datetime = re.search(r'(\[.+\]) (\[.+\].+)', trace).group(2)
- logging.debug("T: " + trace_without_datetime)
-
- def spy_callback(self, spy):
- '''spy with machine name pre-pended'''
- logging.debug("S: [{}] {}".format(self.name, spy))
-
- def outer_state_entry_signal(self, e):
- self.subscribe(Event(signal=signals.BROADCAST))
- self.scribble("hello from outer_state")
- status = return_status.HANDLED
- return status
-
- def outer_state_init_signal(self, e):
- self.scribble("init")
- status = self.trans(self.middle_state)
- return status
-
- def outer_state_hook(self, e):
- status = return_status.HANDLED
- self.scribble("run some code, but don't transition")
- return status
-
- def outer_state_send_broadcast(self, e):
- status = return_status.HANDLED
- self.publish(Event(signal=signals.BROADCAST))
- return status
-
- def outer_state_broadcast(self, e):
- status = return_status.HANDLED
- self.scribble("received broadcast")
- return status
-
- def outer_state_reset(self, e):
- status = self.trans(self.outer_state)
- return status
-
- def outer_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting the outer_state")
- return status
-
- def middle_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.scribble("arming one-shot")
- self.post_fifo(Event(signal=signals.Ready),
- times=1,
- period=1.0,
- deferred=True)
- return status
-
- def middle_state_ready(self, e):
- status = self.trans(self.inner_state)
- return status
-
- def middle_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.cancel_events(Event(signal=signals.Ready))
- return status
-
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.times_in_inner += 1
- self.scribble(
- "hello from inner_state {}".format(self.times_in_inner))
- return status
-
- def inner_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting inner_state")
- return status
-
- class F2(F1):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.scribble("hello from new inner_state")
- return status
-
- def inner_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting new inner_state")
- return status
-
- if __name__ == '__main__':
-
- f1 = F1(
- "f1",
- live_trace=True,
- live_spy=True,
- )
-
- f2 = F2(
- "f2",
- live_trace=True,
- live_spy=True,
- )
-
- f1.start_at(f1.outer_state)
- f1.post_fifo(Event(signal=signals.Hook))
- f1.post_fifo(
- Event(signal=signals.Reset),
+ # simple_state_15.py
+ import re
+ import time
+ import logging
+ from functools import partial
+
+ from miros import Event
+ from miros import signals
+ from miros import Factory
+ from miros import return_status
+ from miros import ThreadSafeAttributes
+
+ class F1(Factory, ThreadSafeAttributes):
+
+ _attributes = ['times_in_inner']
+
+ def __init__(self, name, log_file_name=None,
+ live_trace=None, live_spy=None):
+
+ super().__init__(name)
+
+ self.live_trace = \
+ False if live_trace == None else live_trace
+ self.live_spy = \
+ False if live_spy == None else live_spy
+
+ self.log_file_name = \
+ 'simple_state_15.log' if log_file_name == None else log_file_name
+
+ # clear our log every time we run this program
+ with open(self.log_file_name, "w") as fp:
+ fp.write("")
+
+ logging.basicConfig(
+ format='%(asctime)s %(levelname)s:%(message)s',
+ filename=self.log_file_name,
+ level=logging.DEBUG)
+
+ self.register_live_spy_callback(partial(self.spy_callback))
+ self.register_live_trace_callback(partial(self.trace_callback))
+
+ self.outer_state = self.create(state="outer_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.outer_state_entry_signal). \
+ catch(signal=signals.INIT_SIGNAL,
+ handler=self.outer_state_init_signal). \
+ catch(signal=signals.Hook,
+ handler=self.outer_state_hook). \
+ catch(signal=signals.Send_Broadcast, \
+ handler=self.outer_state_send_broadcast). \
+ catch(signal=signals.BROADCAST, \
+ handler=self.outer_state_broadcast). \
+ catch(signal=signals.Reset,
+ handler=self.outer_state_reset). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.outer_state_exit_signal). \
+ to_method()
+
+ self.middle_state = self.create(state="middle_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.middle_state_entry_signal). \
+ catch(signal=signals.Ready,
+ handler=self.middle_state_ready). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.middle_state_exit_signal). \
+ to_method()
+
+ self.inner_state = self.create(state="inner_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.inner_state_entry_signal). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.inner_state_exit_signal). \
+ to_method()
+
+ self.nest(self.outer_state, parent=None). \
+ nest(self.middle_state, parent=self.outer_state). \
+ nest(self.inner_state, parent=self.middle_state)
+
+ def trace_callback(self, trace):
+ '''trace without datetime-stamp'''
+ trace_without_datetime = re.search(r'(\[.+\]) (\[.+\].+)', trace).group(2)
+ logging.debug("T: " + trace_without_datetime)
+
+ def spy_callback(self, spy):
+ '''spy with machine name pre-pended'''
+ logging.debug("S: [{}] {}".format(self.name, spy))
+
+ def outer_state_entry_signal(self, e):
+ self.subscribe(Event(signal=signals.BROADCAST))
+ self.scribble("hello from outer_state")
+ status = return_status.HANDLED
+ return status
+
+ def outer_state_init_signal(self, e):
+ self.scribble("init")
+ status = self.trans(self.middle_state)
+ return status
+
+ def outer_state_hook(self, e):
+ status = return_status.HANDLED
+ self.scribble("run some code, but don't transition")
+ return status
+
+ def outer_state_send_broadcast(self, e):
+ status = return_status.HANDLED
+ self.publish(Event(signal=signals.BROADCAST))
+ return status
+
+ def outer_state_broadcast(self, e):
+ status = return_status.HANDLED
+ self.scribble("received broadcast")
+ return status
+
+ def outer_state_reset(self, e):
+ status = self.trans(self.outer_state)
+ return status
+
+ def outer_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting the outer_state")
+ return status
+
+ def middle_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("arming one-shot")
+ self.post_fifo(Event(signal=signals.Ready),
times=1,
- period=2.0,
- deferred=True
- )
-
- f2.start_at(f2.inner_state)
- f2.post_fifo(Event(signal=signals.Hook))
- f2.post_fifo(Event(signal=signals.Reset))
- f1.post_fifo(Event(signal=signals.Send_Broadcast))
-
- # delay long enough so we can see how the program behaves in time
- time.sleep(4.00)
-
- # read information from other threads
- print("f1 was in its inner state {} times".format(f1.times_in_inner))
- print("f2 was in its inner state {} times".format(f2.times_in_inner))
-
- Running this program will provide the following output:
-
- .. code-block:: python
-
- f1 was in its inner state 2 times
- f2 was in its inner state 0 times
-
- The f1 statechart properly reports how many times it was in its inner_state.
- The f2 inner_state doesn't write to the ``times_in_inner`` property, so it's
- output only shows how that property was initialized.
-
- Let's look at the property code in isolation from the rest of the statechart:
-
- .. code-block:: python
- :emphasize-lines: 1
- :linenos:
-
- # INITIALIZATION CODE TAKEN FROM __init__
- # set up a thread safe ring buffer of size 1
- self._times_in_inner = deque(maxlen=1)
- self._times_in_inner.append(0)
- # ...
- # PROPERTY methods used to control the deque
- @property
- def times_in_inner(self):
- return self._times_in_inner[-1]
-
- @times_in_inner.setter
- def times_in_inner(self, value):
- self._times_in_inner.append(value)
- # ...
- # CODE FROM WITHIN STATECHART using the property
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.times_in_inner += 1
- self.scribble(
- "hello from inner_state {}".format(self.times_in_inner))
- return status
- # ...
- # CODE OUTSIDE OF STATECHART accessing the property
- print("f1 was in its inner state {} times".format(f1.times_in_inner))
-
- The initialization code on lines 3-4 of this listing, creates a private deque
- ring-buffer which can hold one item, then pushes a zero into this queue. Since
- our ``_time_in_inner`` deque is a ring buffer of size 1, when we ``append`` new
- information into it, it's old information is shifted out of the ring (deleted).
-
- We see this kind of ``append`` taking place in the ``times_in_inner`` setter
- method on lines 12 to 13. The value is shifted into the deque and the old information
- is pushed out. This is a thread safe activity; if more than one thread is
- accessing this method at once, they don't both get to perform the action at the
- same time. One will get its turn, then the other will get its turn.
-
- The ``times_in_inner`` getter method described in lines 7-9 of the listing
- shows us how we can access our information from within or outside of our
- statechart's thread. We only read the latest member of the deque. Since our
- deque is of size one, there is only one thing to read in it anyway.
-
- We can see how this property is used within the statechart's thread on line 18. The
- ``self.times_in_inner += 1`` calls the getter method 8-9, adds one to the result
- then calls the setter method (12-13) which appends the result into the deque,
- shifting the old information out.
-
- We can see how the ``times_in_inner`` property is accessed outside of the
- statechart thread on line 24. The main thread accesses the getter method 8-9, and
- reports its returned value in a print statement.
-
- As of miros 4.1.3, you could create the same thread-safe-attribute like
- this:
-
- .. code-block:: python
-
- from miros import Factory
- # ...
- from miros import ThreadSafeAttributes
-
- class F1(Factory, ThreadSafeAttributes):
- _attribute = ['times_in_inner']
-
- def __init__(self, name, log_file_name=None,
- live_trace=None, live_spy=None):
- # ...
-
- The ThreadSafeAttributes class contains code which automatically makes the
- deque, initializes and wraps the deque within a property. To build such
- attributes, we place the thread-safe-attribute names in a list and assign it to
- ``_attributes``, as seen above. If you would like to read more about this,
- consider:
+ period=1.0,
+ deferred=True)
+ return status
+
+ def middle_state_ready(self, e):
+ status = self.trans(self.inner_state)
+ return status
+
+ def middle_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.cancel_events(Event(signal=signals.Ready))
+ return status
+
+ def inner_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.times_in_inner += 1
+ self.scribble(
+ "hello from inner_state {}".format(self.times_in_inner))
+ return status
+
+ def inner_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting inner_state")
+ return status
+
+ class F2(F1):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ def inner_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("hello from new inner_state")
+ return status
+
+ def inner_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting new inner_state")
+ return status
+
+ if __name__ == '__main__':
+
+ f1 = F1(
+ "f1",
+ live_trace=True,
+ live_spy=True,
+ )
+
+ f2 = F2(
+ "f2",
+ live_trace=True,
+ live_spy=True,
+ )
+
+ f1.start_at(f1.outer_state)
+ f1.post_fifo(Event(signal=signals.Hook))
+ f1.post_fifo(
+ Event(signal=signals.Reset),
+ times=1,
+ period=2.0,
+ deferred=True
+ )
+
+ f2.start_at(f2.inner_state)
+ f2.post_fifo(Event(signal=signals.Hook))
+ f2.post_fifo(Event(signal=signals.Reset))
+ f1.post_fifo(Event(signal=signals.Send_Broadcast))
+
+ # delay long enough so we can see how the program behaves in time
+ time.sleep(4.00)
+
+ # read information from other threads
+ print("f1 was in its inner state {} times".format(f1.times_in_inner))
+ print("f2 was in its inner state {} times".format(f2.times_in_inner))
+
+So where is the lock?
+
+It's hidden from view. The ``times_in_inner`` is a kind of ``@property`` and
+the variable that holds its information is protected by another hidden variable
+that is the lock.
+
+Running this program will provide the following output:
+
+.. code-block:: python
- * :ref:`Sharing attributes between threads (ActiveObjects) `
- * :ref:`Sharing attributes between threads (Factories)`
+ f1 was in its inner state 2 times
+ f2 was in its inner state 0 times
+
+The f1 statechart properly reports how many times it was in its inner_state.
+The f2 inner_state doesn't write to the ``times_in_inner`` property, so it's
+output only shows how that property was initialized.
+
+Let's look at the thread safe code in isolation:
+
+.. code-block:: python
+
+ from miros import Factory
+ # ...
+ from miros import ThreadSafeAttributes
+
+ class F1(Factory, ThreadSafeAttributes):
+ _attribute = ['times_in_inner'] # Uses a metaclass to make the
+ # times_in_inner property, with its
+ # protecting lock
+
+ def __init__(self, name, log_file_name=None,
+ live_trace=None, live_spy=None):
+ # ...
+ self.times_in_inner = 0
+
+ def some_state(self, e):
+ # ..
+ # Inside of the state thread small operations on the times_in_inner
+ # attribute can use used in a thread safe way
+ print(self.times_in_inner) # safe
+ a = self.times_in_inner # safe
+ self.times_in_inner = 1 # safe
+ self.times_in_inner += 1 # safe
+ self.times_in_inner += 2 * self.times_in_inner # NOT safe
+ self.times_in_inner = self.times_in_inner + 1 # NOT safe
+ self.times_in_inner = 2 * self.times_in_inner # NOT safe
+
+The ``ThreadSafeAttributes`` class behaves like a macro, wrapping the getting
+and setting of the thread safe attribute within a thread lock. It also wraps
+simple, ``+=``, ``-=``, ..., ``<<=`` statements within a lock. But that's it.
+It can't protect other types of statements from race conditions. If you need to
+use your thread safe attribute to perform more complex operations, use a
+temporary variable and copy the results into the thread safe attribute when you
+are done.
+
+Better yet, share information using published events. But, the thread safe
+attributes feature is very useful when you are sharing information between a
+statechart and a thread which is not a statechart, like main.
+
+.. note::
+
+ Accessing a thread safe attribute will be very slow. In the background
+ the ``ThreadSafeAttributes`` uses a metaclass, and the descriptor protocol.
+ Within the descriptor protocol it uses the ``inspect`` library to read the
+ previous line of code and compares it to a regular expression. Keep this in
+ mind when you use this feature.
+
+* :ref:`Sharing attributes between threads (ActiveObjects) `
+* :ref:`Sharing attributes between threads (Factories)`
+
+If you have gotten this far, you have a good handle on how to use this library
+and all of its features. But you can take it to another level though. Your
+statecharts can send encrypted messages to one another and act in concert while
+running on different machines. To see how to do this, look at the
+`miros-rabbitmq `_ library.
----
diff --git a/doc/thread_safe_attributes.rst b/doc/thread_safe_attributes.rst
index a3f8f49..06d9fc2 100644
--- a/doc/thread_safe_attributes.rst
+++ b/doc/thread_safe_attributes.rst
@@ -1,521 +1,549 @@
-.. _thread_safe_attributes-thread-safe-attributes:
-
-Thread Safe Attributes
-======================
-
-If you use a statechart, your program is multi-threaded.
-
-Sometimes, you will want to access an attribute of your statechart from another
-thread, like the main part of your program. When you do this, you are trying to
-access memory that could be changed in one thread while it is being read in by
-another thread.
-
-To see why this is an issue imagine using a calculator to solve a simple math
-problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
-following equation:
-
-.. code-block:: python
-
- b = a*cos(0.45) + 3*a^1.2
-
-Seems simple enough. Suppose you pick a straight-forward strategy:
-
- * mark down the value of ``a`` on a piece of paper so you can reference it as you work
- * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
- * then add these results together to find ``b``
-
-But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
-paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
-your desk. You don't notice it. When you get to the ``3*a^1.2`` part of the
-calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
-
-This is called a **race condition**. Here our ``a`` variable was shared between
-two threads, you and the other person. When you program with multiple
-concurrent processes/threads and you share memory, you are exposed to this kind
-of problem.
-
-A simple way to avoid such a situation is to not share the temporary paper in
-the first place. Do not use shared attributes.
-
-Another way to deal with it is to have one thread change a shared attribute and
-have the other thread read the shared attribute. But, this will require that
-maintenance developers understand there are hidden rules in your codebase;
-they could innocently change something an introduce extremely subtle bugs.
-
-Typically, shared variables are protected using thread locks. A lock is a flag
-which works across multiple threads. You can lock the object for reading and
-writing while you use it. In our example, we would lock ``a`` in its ``0.35``
-state while calculating both sub-parts of our problem then unlock it when we are
-done. The other process would wait until the thread-lock cleared, then
-they would change the value of ``a`` to ``0.3`` and do their own work. So,
-there is a cost, you block one thread while waiting for the other to work, and
-you have to share lock variables across all of your threads. It is easy to
-screw this up, and it is tough to test for race conditions.
-
-But why is it hard to test for race conditions? As of Python 3, a thread will
-run for 15 milliseconds before Python passes control to another thread. Most of
-the time, the common memory that is used by both threads will work as you expect
-it will. Infrequently a thread switch will occur midway through a non-atomic
-operation, where some shared value is to be changed by the other
-thread. After this unlikely event, your thread will re-gain control and finish
-its calculation producing the wrong answer.
-
-These kinds of bugs are more probabilistic in nature, than deterministic;
-Python's access to the system clock is jittery. The timing between two Python
-threads will never be the same for every two runs of the program (it's like
-playing a slot machine) so, it will be hard for you to reproduce your issue.
-
-The miros library accepts that people will want to access a statechart's
-internal attributes from the outside. Significant efforts have been made to
-make this kind of activity easy for you to do in a "thread-safe" manner. The
-``ThreadSafeAttributes`` class was constructed to eat the complexity of making
-thread-safe attributes by wrapping "getting" (use of the ".") and "setting"
-operations (use of the "=") within thread-safe locks. In addition to this, the
-non-atomic "+=", "-=" ... "//=" statements using thread-safe attributes were
-also wrapped within locks. For more complex situations, the
-thread-safety features provided by the ``ThreadSafeAttributes`` class can be
-used get to get the thread lock explicitly.
-
-I will introduce these ideas gradually through a set of examples. Let's
-begin by looking at four interacting threads (possible race conditions are
-highlighted):
-
-.. code-block:: python
- :emphasize-lines: 18, 19, 31, 32
- :linenos:
-
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- from miros import ThreadSafeAttributes
-
- class GetLock1(ThreadSafeAttributes):
- _attributes = ['thread_safe_attr_1']
-
- def __init__(self, evt):
- '''running in main thread'''
- self.evt = evt
- self.thread_safe_attr_1 = 0
-
- def thread_method_1(self):
- '''running in th1 thread'''
- while(self.evt.is_set()):
- self.thread_safe_attr_1 += 1
- print("th1: ", self.thread_safe_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running in main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running in th1 thread'''
- while(self.evt.is_set()):
- self.gl1.thread_safe_attr_1 -= 1
- print("th2: ", self.gl1.thread_safe_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running in main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running in killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- # main thread:
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='killer', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-The ``GetLock1`` class inherits from the ``ThreadSafeAttributes`` class, which
-uses a metaclass to give it access to the following syntax (seen on line 8 of
-the above example):
-
-.. code-block:: python
-
- _attributes = ['thread_safe_attr_1']
-
-The ``ThreadSafeAttributes`` class tries to protect you. When we write the
-``_attributes = ['thread_safe_attr_1']`` syntax, ``ThreadSafeAttributes`` creates
-a set of hidden attributes, which are wrapped inside of a `descriptor protocol
-`_ (think @property). One of
-the hidden attributes, `_lock` is a `threading.RLock
-`_. It is
-used to lock and unlock itself around accesses to the other hidden attribute
-`_value`. Essentially this means that this code:
-
-.. code-block:: python
-
- gl1.thread_safe_attr_1
- gl1.thread_safe_attr_1 = 1
-
-... would turn into something like this before it is run:
-
-.. code-block:: python
-
- with gl1._lock:
- gl1.thread_safe_attr_1
-
- with gl1._lock:
- gl1.thread_safe_attr_1 = 1
-
-
-.. note::
-
- A lot of Python libraries provide features to change simple syntax into more
- complex and specific syntax prior to having it run. If this library was
- written in c, this kind of work would be done inside of a macro, and the
- preprocessor would create custom c-code before it was compiled into an
- executable.
-
-The ``ThreadSafeAttributes`` class also tries to protect your code from race
-conditions introduced by non-atomic ``+=`` statements acting on shared
-attributes:
-
-.. code-block:: python
-
- gl1.thread_safe_attr_1 += 1
-
-When using the ``ThreadSafeAttributes`` class the above code turns into something like this:
-
-.. code-block:: python
-
- with gl1._lock:
- temp = gl1.thread_safe_attr_1
- temp = temp + 1
- gl1.thread_safe_attr_1 = temp
-
-So the ``ThreadSafeAttributes`` class protects calls to the
-seemingly-innocuous-looking, yet dangerous, "+=", "-=", ... "//=" family of
-Python calls. They are dangerous because they are not-atomic and can cause race
-conditions if they are applied to attributes shared across threads.
-
-So our example, written without the ``ThreadSafeAttributes`` class, but with the
-same protections would look like this (shared attributes protections
-highlighted):
-
-.. code-block:: python
- :emphasize-lines: 11, 18-21, 33-36
- :linenos:
-
- place code here
- import time
- from threading import RLock
- from threading import Thread
- from threading import Event as ThreadEvent
-
- class GetLock1():
-
- def __init__(self, evt):
- '''running within main thread'''
- self._rlock = RLock()
- self.evt = evt
- self.thread_safe_attr_1 = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- while(self.evt.is_set()):
- with self._rlock:
- self.thread_safe_attr_1 += 1
- with self._rlock:
- print("th1: ", self.thread_safe_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- while(self.evt.is_set()):
- with self.gl1._rlock:
- self.gl1.thread_safe_attr_1 -= 1
- with self.gl1._rlock:
- print("th2: ", self.gl1.thread_safe_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-We haven't looked at any code results yet. Let's run it and see what it does:
-
-.. code-block:: bash
-
- $python thread_safe_attributes_2.py
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th2: -1
- th1: 0
- th1: 1
- th2: 0
-
-We see that the number oscillates about 0. If we remove the time delays at the
-bottom of the thread functions, you will see wild oscillation in this number,
-since one thread by chance will get many more opportunities to run. So you can
-see that it might be hard to reproduce precisely two identical traces of the
-program output.
-
-Ok, now for something scary, let's look at our code without thread-locks (the
-race conditions are highlighted):
-
-.. code-block:: python
- :emphasize-lines: 15, 16, 28, 29
- :linenos:
-
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- class GetLock1():
-
- def __init__(self, evt):
- '''running within main thread'''
- self.evt = evt
- self.thread_race_attr_1 = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- while(self.evt.is_set()):
- self.thread_race_attr_1 += 1
- print("th1: ", self.thread_race_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- while(self.evt.is_set()):
- self.gl1.thread_race_attr_1 -= 1
- print("th2: ", self.gl1.thread_race_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-I changed the ``thread_safe_attr_1`` name to ``thread_race_attr_1`` to make a
-point. The highlighted code shows where race conditions can occur. If we run
-the code we see:
-
-.. code-block:: bash
-
- python thread_safe_attributes_3_unsafe.py
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th2: -1
- th1: 0
- th1: 1
- th2: 0
- th1: 1
- th2: 0
-
-Which looks almost exactly the same as the last run. Race conditions are very
-hard to find.
-
-Let's move back to our original example, suppose we absolutely needed
-to run calculations on the ``thread_safe_attr_1`` in more than one thread (which
-I can't see the need for). I'll change the name of ``thread_safe_attr_1`` to
-``a``. The ``ThreadSafeAttributes`` class can not implicitly protect you in such
-situations, but what it can do is give you the lock and you can use it to
-protect your own code (highlighting how to get the lock):
-
-.. code-block:: python
- :emphasize-lines: 18, 34
- :linenos:
-
- import math
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- from miros import ThreadSafeAttributes
-
- class GetLock1(ThreadSafeAttributes):
- _attributes = ['a']
-
- def __init__(self, evt):
- '''running within main thread'''
- self.evt = evt
- self.a = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- _, _lock = self.a
- while(self.evt.is_set()):
- with _lock:
- self.a = 0.35
- b = self.a * math.cos(0.45) + 3 * self.a ** 1.2
- print("th1: ", b)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- _, _lock = self.gl1.a
- while(self.evt.is_set()):
- with _lock:
- self.gl1.a = 0.30
- b = self.gl1.a * math.cos(0.45) + 3 * self.gl1.a ** 1.2
- print("th2: ", b)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- # main thread:
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-The lock can be obtained by calling ``_, _lock = ``.
-
-This is a little nasty piece of metaprogramming that could baffle a beginner or
-anyone who looks at the thread safe attribute. Most of the time your thread
-safe attribute acts as an attribute, but other times it acts as an iterable,
-what is going on? It only acts as an interable when proceeded by ``_, _lock``.
-If you use this technique in one of your threads, you must use it in all of your
-threads.
-
-Once again I recommend against performing calculations directly on your shared
-attributes. Instead, copy their variable into a temp, perform a calculation
-then assign the results into them.
-
-.. note::
-
- The ``ThreadSafeAttributes`` feature actually reads the last line of code you
- have written, the behaves differently depending on what you have written. It
- is because of this feature it can release it's lock in what looks like a
- syntactically inconsistent way.
-
-:ref:`back to examples `
+
+ *The best is the enemy of the good.*
+
+ -- Voltaire
+
+.. _thread_safe_attributes-thread-safe-attributes:
+
+Thread Safe Attributes
+======================
+
+If you use a miros statechart, your program is multi-threaded.
+
+Sometimes, you will want to access an attribute of your statechart from another
+thread, like the main part of your program. When you do this, you are trying to
+access memory that could be changed in one thread while it is being read in by
+another thread.
+
+To see why this is an issue imagine using a calculator to solve a simple math
+problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
+following equation:
+
+.. code-block:: python
+
+ b = a*cos(0.45) + 3*a^1.2
+
+Seems simple enough. Suppose you pick a straight-forward strategy:
+
+ * mark down the value of ``a`` on a piece of paper so you can reference it as you work
+ * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
+ * then add these results together to find ``b``
+
+But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
+paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
+your desk. You don't notice it. When you get to the ``3*a^1.2`` part of the
+calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
+
+This is called a **race condition**. Here our ``a`` variable was shared between
+two threads, you and the other person. When you program with multiple
+concurrent processes/threads and you share memory, you are exposed to this kind
+of problem.
+
+A simple way to avoid such a situation is to not share the temporary paper in
+the first place. Do not use shared attributes.
+
+Another way to deal with it is to have one thread change a shared attribute and
+have the other thread read the shared attribute. But, this will require that
+maintenance developers understand there are hidden rules in your codebase;
+they could innocently change something an introduce extremely subtle bugs.
+
+Typically, shared variables are protected using thread locks. A lock is a flag
+which works across multiple threads. You can lock the object for reading and
+writing while you use it. In our example, we would lock ``a`` in its ``0.35``
+state while calculating both sub-parts of our problem then unlock it when we are
+done. The other process would wait until the thread-lock cleared, then
+they would change the value of ``a`` to ``0.3`` and do their own work. So,
+there is a cost, you block one thread while waiting for the other to work, and
+you have to share lock variables across all of your threads. It is easy to
+screw this up, and it is tough to test for race conditions.
+
+But why is it hard to test for race conditions? As of Python 3, a thread will
+run for 15 milliseconds before Python passes control to another thread. Most of
+the time, the common memory that is used by both threads will work as you expect
+it will. Infrequently a thread switch will occur midway through a non-atomic
+operation, where some shared value is to be changed by the other
+thread. After this unlikely event, your thread will re-gain control and finish
+its calculation producing the wrong answer.
+
+These kinds of bugs are more probabilistic in nature, than deterministic;
+Python's access to the system clock is jittery. The timing between two Python
+threads will never be the same for every two runs of the program (it's like
+playing a slot machine) so, it will be hard for you to reproduce your issue.
+
+The miros library accepts that people will want to access a statechart's
+internal attributes from the outside. Significant efforts have been made to
+make this kind of activity easy for you to do in a "thread-safe" manner. The
+``ThreadSafeAttributes`` class was constructed to eat the complexity of making
+thread-safe attributes by wrapping "getting" (use of the ".") and "setting"
+operations (use of the "=") within thread-safe locks. In addition to this, the
+non-atomic "+=", "-=" ... "//=" statements using thread-safe attributes were
+also wrapped within locks. For more complex situations, the
+thread-safety features provided by the ``ThreadSafeAttributes`` class can be
+used to get the thread lock explicitly.
+
+I will introduce these ideas gradually through a set of examples. Let's
+begin by looking at four interacting threads (possible race conditions are
+highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 18, 19, 31, 32
+ :linenos:
+
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ from miros import ThreadSafeAttributes
+
+ class GetLock1(ThreadSafeAttributes):
+ _attributes = ['thread_safe_attr_1']
+
+ def __init__(self, evt):
+ '''running in main thread'''
+ self.evt = evt
+ self.thread_safe_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running in th1 thread'''
+ while(self.evt.is_set()):
+ self.thread_safe_attr_1 += 1
+ print("th1: ", self.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running in main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running in th1 thread'''
+ while(self.evt.is_set()):
+ self.gl1.thread_safe_attr_1 -= 1
+ print("th2: ", self.gl1.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running in main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running in killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ # main thread:
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='killer', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+The ``GetLock1`` class inherits from the ``ThreadSafeAttributes`` class, which
+uses a metaclass to give it access to the following syntax (seen on line 8 of
+the above example):
+
+.. code-block:: python
+
+ _attributes = ['thread_safe_attr_1']
+
+The ``ThreadSafeAttributes`` class tries to protect you. When we write the
+``_attributes = ['thread_safe_attr_1']`` syntax, ``ThreadSafeAttributes`` creates
+a set of hidden attributes, which are wrapped inside of a `descriptor protocol
+`_ (think @property). One of
+the hidden attributes, `_lock` is a `threading.RLock
+`_. It is
+used to lock and unlock itself around accesses to the other hidden attribute
+`_value`. Essentially this means that this code:
+
+.. code-block:: python
+
+ gl1.thread_safe_attr_1
+ gl1.thread_safe_attr_1 = 1
+
+... would turn into something like this before it is run:
+
+.. code-block:: python
+
+ with gl1._lock:
+ gl1.thread_safe_attr_1
+
+ with gl1._lock:
+ gl1.thread_safe_attr_1 = 1
+
+
+.. note::
+
+ A lot of Python libraries provide features to change simple syntax into more
+ complex and specific syntax prior to having it run. If this library was
+ written in c, this kind of work would be done inside of a macro, and the
+ preprocessor would create custom c-code before it was compiled into an
+ executable.
+
+The ``ThreadSafeAttributes`` class also tries to protect your code from race
+conditions introduced by non-atomic ``+=`` statements acting on shared
+attributes:
+
+.. code-block:: python
+
+ gl1.thread_safe_attr_1 += 1
+
+When using the ``ThreadSafeAttributes`` class the above code turns into something like this:
+
+.. code-block:: python
+
+ with gl1._lock:
+ temp = gl1.thread_safe_attr_1
+ temp = temp + 1
+ gl1.thread_safe_attr_1 = temp
+
+So the ``ThreadSafeAttributes`` class protects calls to the
+seemingly-innocuous-looking, yet dangerous, "+=", "-=", ... "//=" family of
+Python calls. They are dangerous because they are not-atomic and can cause race
+conditions if they are applied to attributes shared across threads.
+
+So our example, written without the ``ThreadSafeAttributes`` class, but with the
+same protections would look like this (shared attributes protections
+highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 11, 18-21, 33-36
+ :linenos:
+
+ place code here
+ import time
+ from threading import RLock
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ class GetLock1():
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self._rlock = RLock()
+ self.evt = evt
+ self.thread_safe_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ while(self.evt.is_set()):
+ with self._rlock:
+ self.thread_safe_attr_1 += 1
+ with self._rlock:
+ print("th1: ", self.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ while(self.evt.is_set()):
+ with self.gl1._rlock:
+ self.gl1.thread_safe_attr_1 -= 1
+ with self.gl1._rlock:
+ print("th2: ", self.gl1.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+We haven't looked at any code results yet. Let's run it and see what it does:
+
+.. code-block:: bash
+
+ $python thread_safe_attributes_2.py
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th2: -1
+ th1: 0
+ th1: 1
+ th2: 0
+
+We see that the number oscillates about 0. If we remove the time delays at the
+bottom of the thread functions, you will see wild oscillation in this number,
+since one thread by chance will get many more opportunities to run. So you can
+see that it might be hard to reproduce precisely two identical traces of the
+program output.
+
+Ok, now for something scary, let's look at our code without thread-locks (the
+race conditions are highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 15, 16, 28, 29
+ :linenos:
+
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ class GetLock1():
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self.evt = evt
+ self.thread_race_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ while(self.evt.is_set()):
+ self.thread_race_attr_1 += 1
+ print("th1: ", self.thread_race_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ while(self.evt.is_set()):
+ self.gl1.thread_race_attr_1 -= 1
+ print("th2: ", self.gl1.thread_race_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+I changed the ``thread_safe_attr_1`` name to ``thread_race_attr_1`` to make a
+point. The highlighted code shows where race conditions can occur. If we run
+the code we see:
+
+.. code-block:: bash
+
+ python thread_safe_attributes_3_unsafe.py
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th2: -1
+ th1: 0
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+
+Which looks almost exactly the same as the last run. Race conditions are very
+hard to find.
+
+Let's move back to our original example, suppose we absolutely needed
+to run calculations on the ``thread_safe_attr_1`` in more than one thread (which
+I can't see the need for). I'll change the name of ``thread_safe_attr_1`` to
+``a``. The ``ThreadSafeAttributes`` class can not implicitly protect you in such
+situations, but what it can do is give you the lock and you can use it to
+protect your own code (highlighting how to get the lock):
+
+.. code-block:: python
+ :emphasize-lines: 18, 34
+ :linenos:
+
+ import math
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ from miros import ThreadSafeAttributes
+
+ class GetLock1(ThreadSafeAttributes):
+ _attributes = ['a']
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self.evt = evt
+ self.a = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ _, _lock = self.a
+ while(self.evt.is_set()):
+ with _lock:
+ self.a = 0.35
+ b = self.a * math.cos(0.45) + 3 * self.a ** 1.2
+ print("th1: ", b)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ _, _lock = self.gl1.a
+ while(self.evt.is_set()):
+ with _lock:
+ self.gl1.a = 0.30
+ b = self.gl1.a * math.cos(0.45) + 3 * self.gl1.a ** 1.2
+ print("th2: ", b)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ # main thread:
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+The lock can be obtained by calling ``_, _lock = ``.
+
+This nasty little piece of metaprogramming could baffle a beginner or anyone who
+looks at the thread safe attribute: Most of the time your thread-safe attribute
+acts as an attribute, but other times it acts as an iterable, what is going on?
+It only acts as an iterable when proceeded by ``_, _lock``. **If you use this
+technique in one of your threads, you must also explicitly get the lock in all
+other threads that share the attribute.**
+
+This lock-access feature was added for difficult situations, where the client
+code absolutely needs the lock, maybe for advanced database calls or that kind
+of thing.
+
+**I recommend against explicitely getting a lock** and performing calculations
+directly on your shared attributes.
+
+Instead, copy their contents into a local variable (automatically locked) ,
+perform a calculation using local variables, then assign the results back into
+the shared attribute (automatically locked).
+
+In our example, we don't need to use shared attribute at all, so we shouldn't.
+The example was arbitrary, a better way to perform the calculation can be seen
+in the following code listing. If we needed to place the ``0.3`` back into the
+shared-attribute, we can do that, but we keep the shared-attribute out of our
+equation. The equation will use non-shared, thread-safe, local variables which
+are placed on the stack during a thread's context switch.
+
+.. code-block:: python
+
+ # code which doesn't require an explicit lock
+ temp = 0.30
+ b = temp * math.cos(0.45) + 3 * temp ** 1.2
+ print("thr2: ", b)
+ # this code will be implicitly locked by ThreadSafeAttributes
+ self.gl1.a = temp
+
+.. note::
+
+ The ``ThreadSafeAttributes`` feature actually reads the last line of code you
+ have written, the behaves differently depending on what you have written. It
+ is because of this feature it can release it's lock in what looks like a
+ syntactically inconsistent way.
+
+:ref:`back to examples `
diff --git a/doc/towardsthefactoryexample.rst b/doc/towardsthefactoryexample.rst
index 521b4d6..c81c83a 100644
--- a/doc/towardsthefactoryexample.rst
+++ b/doc/towardsthefactoryexample.rst
@@ -1,786 +1,786 @@
- *You know you are working with clean code when each routine you read turns out to
- be pretty much what you expected. You can call it beautiful code when the code
- also makes it look like the language was made for the problem.*
-
- -- Ward Cunningham
-
-.. _towardsthefactoryexample-towards-a-factory:
-
-Using and Unwinding a Factory
-=============================
-
-.. image:: _static/factory1.svg
- :target: _static/factory1.pdf
- :align: center
-
-.. _towardsthefactoryexample-example-summary:
-
-Example Summary
----------------
-1. :ref:`Standard Approach to Writing State Methods`
-2. :ref:`Registering Callbacks to Specific Events`
-3. :ref:`Creating a Statechart Using Templates`
-4. :ref:`Creating a Statechart Using A Factory`
-5. :ref:`Unwinding a Factory State Method`
-
-.. _towardsthefactoryexample-why-you-would-want-a-factory:
-
-In this example I will walk you through how to hand-code a simple state method
-then show how that same method could be written for you automatically. Then I
-will show how to re-flatten a statechart, so that you can copy this code back
-into your design to make it easier to debug. (Like looking at preprocessor
-results in c).
-
-Why a Factory?
---------------
-The event processor uses the organization of your state methods, who their
-parents are and how they relate to each other as if they defined a complicated
-data structure. These state methods contain your application code too, but
-they `are` the nodes of your graph; they define the topology of your
-statechart.
-
-When you send an event which will cause a transition across multiple states with
-complicated entry/exit/init event triggering to provide the Harel Formalism,
-you don't have to worry about how it is implemented, you just need to ensure
-that you have framed in your state methods with enough structure that the event
-processing algorithm can discover the graph and build out the expected behavior.
-
-This provides the illusion that you are using a completely different type of
-programming language, but it's still all Python. Your state methods are just
-being called over and over again with different arguments.
-
-Miro Samek describes this as "an inversion of control". By using his event
-processing algorithm, you are packing the management complexity of the
-topological search into the bottom part of your software system. By pushing
-this to the bottom, you can focus on writing concise descriptions of how your
-system should behave without concerning yourself with how to implement this
-behavior, the algorithm solves that problem. You just need to build the map.
-
-But to do this, the event processor expects all of your state methods to have a
-specific shape. Their method signatures have to look a certain way and their
-if-else structures have to be framed-in just right, otherwise the event
-processor will get lost while it's searching for the correct behavior.
-
-Wouldn't it be nice if the library wrote the methods for you too? Well it can,
-you can use a factory to create state method nodes, then link in event
-callbacks and assign parents at run time. The benefit of such an approach is
-that you can avoid the strangeness of a state method. It will become harder
-for a maintenance developer to accidentally break your statechart by making
-something that looks like an innocuous change. The factory hides the
-topological structure of your state methods behind another layer of
-indirection.
-
-However, if you use this library to write your state methods for you, you are
-placing yet another layer of abstraction between you and your design. A bug
-might be even harder to find than it was before. The nice thing about the
-state methods is that they are easy to understand, they are flat, and you can
-literally see the code and break within it for debugging. The cognitive
-difficulty experienced while trouble shooting a flat state method is much less
-than it would be for something that is auto-generated.
-
-
-.. _towardsthefactoryexample-standard-approach:
-
-Standard Approach to Writing State Methods
-------------------------------------------
-
-.. image:: _static/factory1.svg
- :target: _static/factory1.pdf
- :align: center
-
-To create the above diagram we would define three state methods, ``c``, ``c1``
-and ``c2`` and an active object.
-
-.. code-block:: python
- :emphasize-lines: 42
-
- import time
- from miros import spy_on, pp
- from miros import ActiveObject
- from miros import signals, Event, return_status
-
-
- @spy_on
- def c(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.INIT_SIGNAL):
- status = chart.trans(c1)
- elif(e.signal == signals.BB):
- status = chart.trans(c)
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def c1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.A):
- status = chart.trans(c1)
- else:
- status, chart.temp.fun = return_status.SUPER, c
- return status
-
-
- @spy_on
- def c2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.A):
- status = chart.trans(c1)
- else:
- status, chart.temp.fun = return_status.SUPER, c
- return status
-
-
- ao = ActiveObject()
- ao.start_at(c2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01) # give your active object a moment to respond
- pp(ao.spy())
-
-An active object has its own thread, so when you want to communicate to it by
-posting an event, you have to give it the briefest opportunity to react.
-This delay is highlighted in the above code.
-
-When the above code is run, it would output this to your terminal:
-
- .. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:c2',
- 'SEARCH_FOR_SUPER_SIGNAL:c',
- 'ENTRY_SIGNAL:c',
- 'ENTRY_SIGNAL:c2',
- 'INIT_SIGNAL:c2',
- '<- Queued:(0) Deferred:(0)',
- 'A:c2',
- 'SEARCH_FOR_SUPER_SIGNAL:c1',
- 'SEARCH_FOR_SUPER_SIGNAL:c2',
- 'EXIT_SIGNAL:c2',
- 'ENTRY_SIGNAL:c1',
- 'INIT_SIGNAL:c1',
- '<- Queued:(0) Deferred:(0)']
-
-We see from the spy log that we had two run to completion events with no
-surprises. Notice that the event processor tried to call the state functions
-with the ``ENTRY_SIGNAL``, ``INIT_SIGNAL`` and ``EXIT_SIGNAL`` as it should
-have, even though our state methods did not handle these events. The handlers
-for these events were left out of the state method examples to keep the code
-compact. This demonstrates that the event processor assumes that a missing
-handler for ``entry``, ``init`` and ``exit`` signals are handled by a state
-method.
-
-.. _towardsthefactoryexample-registering-callbacks-to-specific-events:
-
-Registering Callbacks to Specific Events
-----------------------------------------
-To build our state method code generation we need to create something that is
-common to all state methods. The state method does two different things, it
-responds to events and it returns parent information.
-
-To break this down even more, we can say that it does four things. It asks two
-questions and answers two questions. It asks "How should I respond to the
-events that I care about?" and "Who is my parent?".
-
-Then it answers these questions with information specific to that state method.
-To make something common across all state methods we can ask the questions but
-we can't answer them. The answers will have to be injected into the state
-methods after they have been created.
-
-To be more specific a general state method could look something like this:
-
-.. code-block:: python
- :emphasize-lines: 4-6, 8-11
-
- @spy_on
- def general_state_method(chart, e):
-
- # How should I respond to the events that I care about?
- with chart.signal_callback(e, general_state_method) as fn:
- status = fn(chart, e)
-
- # Who is my parent?
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
-We see that the chart argument provides different context managers,
-``signal_callback`` and ``parent_callback``. It is within these context
-managers that the answers are made.
-
-To inject the information into the chart
-object so that these context managers have something to answer with we can use the
-``register_signal_callback`` and the ``register_parent`` of the active object.
-
-Things should become a bit clearer with an example, reconsider our previous design:
-
-.. image:: _static/factory3.svg
- :target: _static/factory3.pdf
- :align: center
-
-
-.. code-block:: python
- :emphasize-lines: 4, 16, 28
-
- @spy_on
- def tc(chart, e):
-
- with chart.signal_callback(e, tc) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- @spy_on
- def tc1(chart, e):
-
- with chart.signal_callback(e, tc1) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- @spy_on
- def tc2(chart, e):
-
- with chart.signal_callback(e, tc2) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
-To distinguish these state methods from the previous ones we pre-pend their names
-with `t` which stands for template.
-
-These state methods almost look identical, the highlighted lines spell out how
-they are different; the ``signal_callback`` context manager is using the state
-method's name to get its information. Other than that it hardly seems worth
-writing out the code three times.
-
-Now we have to give it the information required to perform the actions we want,
-first we define some callback methods, then we describe how we want our state
-methods to call them.
-
-.. code-block:: python
- :emphasize-lines: 1-11, 13, 15-31
-
- def trans_to_tc(chart, e):
- return chart.trans(tc)
-
- def trans_to_tc1(chart, e):
- return chart.trans(tc1)
-
- def trans_to_tc2(chart, e):
- return chart.trans(tc2)
-
- def do_nothing(chart, e):
- return return_status.HANDLED
-
- ao = ActiveObject()
-
- ao.register_signal_callback(tc, signals.BB, trans_to_tc)
- ao.register_signal_callback(tc, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc, signals.INIT_SIGNAL, trans_to_tc1)
- ao.register_parent(tc, ao.top)
-
- ao.register_signal_callback(tc1, signals.A, trans_to_tc2)
- ao.register_signal_callback(tc1, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc1, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc1, signals.INIT_SIGNAL, do_nothing)
- ao.register_parent(tc1, tc)
-
- ao.register_signal_callback(tc2, signals.A, trans_to_tc1)
- ao.register_signal_callback(tc2, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc2, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc2, signals.INIT_SIGNAL, do_nothing)
- ao.register_parent(tc2, tc)
-
-In the first highlighted block we create four different callback methods. They
-have the same method signature as a state method and they work exactly as they
-would if they were defined within a state method.
-
-The second block is just an instantiation of an active object, it has the event
-processor and it also provides a means to register callback methods for events
-and to register a parent state.
-
-The next block shows how are three state methods are given their information.
-For instance, the event ``BB`` will cause state ``tc`` to transition to itself.
-
-If we run this code like we did in our previous example we would expect to it
-behave the same:
-
-.. code-block:: python
-
- ao.start_at(tc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01) # give your active object a moment to respond
- pp(ao.spy())
-
-If we ran this code, we would see:
-
- .. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:tc2',
- 'SEARCH_FOR_SUPER_SIGNAL:tc',
- 'ENTRY_SIGNAL:tc',
- 'ENTRY_SIGNAL:tc2',
- 'INIT_SIGNAL:tc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:tc2',
- 'SEARCH_FOR_SUPER_SIGNAL:tc1',
- 'SEARCH_FOR_SUPER_SIGNAL:tc2',
- 'EXIT_SIGNAL:tc2',
- 'ENTRY_SIGNAL:tc1',
- 'INIT_SIGNAL:tc1',
- '<- Queued:(0) Deferred:(0)']
-
-.. _towardsthefactoryexample-registering-a-parent-to-a-state-method:
-
-Creating a Statechart Using Templates
--------------------------------------
-We pretty much wrote the same method three times in a row in our :ref:`last
-example`.
-Wouldn't it be nice if something could write the thing for us?
-
-This is exactly what the ``miros.hsm.state_method_template`` does.
-
-It writes the template code within another function, then copies it so that
-this function result is unique in memory, then it renames it and then decorates
-it with some instrumentation.
-
-.. code-block:: python
-
- from miros import spy_on
-
- def state_method_template(name):
-
- def base_state_method(chart, e):
-
- with chart.signal_callback(e, name) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback(name) as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- resulting_function = copy(base_state_method)
- resulting_function.__name__ = name
- resulting_function = spy_on(resulting_function)
- return resulting_function
-
-With this method we can automatically write our state methods then register
-event callbacks and parent states.
-
-Let's re-create our example, this time using this ``state_method_template``
-method:
-
-.. image:: _static/factory4.svg
- :target: _static/factory4.pdf
- :align: center
-
-.. code-block:: python
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- # create the states
- fc = state_method_template('fc')
- fc1 = state_method_template('fc1')
- fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- ao.register_parent(fc2, fc)
-
- # start up the active object and watch what is does
- ao.start_at(fc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(ao.spy())
-
-This is a much more compact version of our map. I removed the registration of
-signals that weren't being used by the design, but more importantly I used the
-``state_method_template`` to create the state methods that could have
-information added to them with the active object registration methods.
-
-The output from this program is:
-
-.. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'EXIT_SIGNAL:fc2',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)']
-
-Which is the expected behavior.
-
-.. _towardsthefactoryexample-using-the-factory-class:
-
-Using the Factory Class
------------------------
-The ``active_object`` module's Factory class provides a syntax which is similar to
-the previous miros version. It has the ``create``, ``catch`` and ``nest``
-methods, but it also extends the other API with ``to_method`` and ``to_code``.
-
-The Factory class wraps the ``register_signal_callback`` and
-``register_parent`` described in the :ref:`previous
-section`
-making syntax that is a bit more concise.
-
-.. image:: _static/factory5.svg
- :target: _static/factory5.pdf
- :align: center
-
-Here is how you could implement this statechart with the ``Factory`` class:
-
-.. code-block:: python
- :emphasize-lines: 15
- :linenos:
-
- from miros import ActiveObject
- from miros import signals, Event, return_status
- from miros import Factory
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- chart = Factory('factory_class_example')
-
- fc = chart.create(state='fc'). \
- catch(signal=signals.B, handler=trans_to_fc). \
- catch(signal=signals.INIT_SIGNAL, handler=trans_to_fc1). \
- to_method()
-
- fc1 = chart.create(state='fc1'). \
- catch(signal=signals.A, handler=trans_to_fc2). \
- to_method()
-
- fc2 = chart.create(state='fc2'). \
- catch(signal=signals.A, handler=trans_to_fc1). \
- to_method()
-
- chart.nest(fc, parent=None). \
- nest(fc1, parent=fc). \
- nest(fc2, parent=fc)
-
- chart.start_at(fc)
- chart.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(chart.spy())
-
-If we ran the above code we would see the expected behavior:
-
-.. code-block:: python
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'INIT_SIGNAL:fc',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'EXIT_SIGNAL:fc1',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)']
-
-
-.. _towardsthefactoryexample-unwinding-a-factory-state-method:
-
-Unwinding a Factory State Method
---------------------------------
-State methods made from factories are hard to debug because you can't actually
-see their code. If you find that you have an issue with such a state method, you
-can unwind it into flat code using the ``to_code`` method. This method outputs a
-string that you can use as a hand written state method.
-
-In the following example, I'll show how we can 'unwind' a design.
-
-.. image:: _static/factory4.svg
- :target: _static/factory4.pdf
- :align: center
-
-First we repeat the work of the last section:
-
-.. code-block:: python
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- # create the states
- fc = state_method_template('fc')
- fc1 = state_method_template('fc1')
- fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- ao.register_parent(fc2, fc)
-
-The ``fc``, ``fc1`` and ``fc2`` objects contain state methods that were
-generated by the framework and their code is hidden within the ``ao`` object.
-
-Now suppose something were to go wrong with this design? An application
-developer would have to know that there are at least four different places to
-look within the miros framework to understand their state method: the
-registration functions, the context managers and in the actual template
-generation function. That would be a lot to keep in their head while they were
-also trying to wrestle with their own design problem.
-
-Instead, they could use the ``to_code`` method, copy the result and write it
-back into the design as flat state methods. In this way they could focus their
-entire attention on their own issue. Here is how they could do it:
-
-.. code-block:: python
-
- print(ao.to_code(fc))
- print(ao.to_code(fc1))
- print(ao.to_code(fc2))
-
-This would output the following:
-
-.. code-block:: python
-
- @spy_on
- def fc(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.BB):
- status = trans_to_fc(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def fc1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc2(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
- @spy_on
- def fc2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
-They could copy these methods and re-write their original code as this, making
-sure that the comment out all of the factory code:
-
-.. code-block:: python
- :emphasize-lines: 11-24,27-40,43-56, 58-61, 66-69,71-74,76-78
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- @spy_on
- def fc(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.BB):
- status = trans_to_fc(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def fc1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc2(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
- @spy_on
- def fc2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
- # create the states
- # fc = state_method_template('fc')
- # fc1 = state_method_template('fc1')
- # fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- # ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- # ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- # ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- # ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- # ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- # ao.register_parent(fc2, fc)
-
- # start up the active object and watch what it does
- ao.start_at(fc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(ao.spy())
-
-The highlighted sections identify all of the changes to the design. New
-flattened state methods were added and the old factory code was commented out.
-If we run this code, we see that it behaves properly:
-
-.. code-block:: python
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'EXIT_SIGNAL:fc2',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)']
-
-Metaprogramming is easy on the person who first writes the code and very hard
-on those that have to maintain or extend the design. Like anything else,
-whether it should be done or not is dependent upon the engineering trade offs.
-
-:ref:`back to examples `
+ *You know you are working with clean code when each routine you read turns out to
+ be pretty much what you expected. You can call it beautiful code when the code
+ also makes it look like the language was made for the problem.*
+
+ -- Ward Cunningham
+
+.. _towardsthefactoryexample-towards-a-factory:
+
+Using and Unwinding a Factory
+=============================
+
+.. image:: _static/factory1.svg
+ :target: _static/factory1.pdf
+ :align: center
+
+.. _towardsthefactoryexample-example-summary:
+
+Example Summary
+---------------
+1. :ref:`Standard Approach to Writing State Methods`
+2. :ref:`Registering Callbacks to Specific Events`
+3. :ref:`Creating a Statechart Using Templates`
+4. :ref:`Creating a Statechart Using A Factory`
+5. :ref:`Unwinding a Factory State Method`
+
+.. _towardsthefactoryexample-why-you-would-want-a-factory:
+
+In this example I will walk you through how to hand-code a simple state method
+then show how that same method could be written for you automatically. Then I
+will show how to re-flatten a statechart, so that you can copy this code back
+into your design to make it easier to debug. (Like looking at preprocessor
+results in c).
+
+Why a Factory?
+--------------
+The event processor uses the organization of your state methods, who their
+parents are and how they relate to each other as if they defined a complicated
+data structure. These state methods contain your application code too, but
+they `are` the nodes of your graph; they define the topology of your
+statechart.
+
+When you send an event which will cause a transition across multiple states with
+complicated entry/exit/init event triggering to provide the Harel Formalism,
+you don't have to worry about how it is implemented, you just need to ensure
+that you have framed in your state methods with enough structure that the event
+processing algorithm can discover the graph and build out the expected behavior.
+
+This provides the illusion that you are using a completely different type of
+programming language, but it's still all Python. Your state methods are just
+being called over and over again with different arguments.
+
+Miro Samek describes this as "an inversion of control". By using his event
+processing algorithm, you are packing the management complexity of the
+topological search into the bottom part of your software system. By pushing
+this to the bottom, you can focus on writing concise descriptions of how your
+system should behave without concerning yourself with how to implement this
+behavior, the algorithm solves that problem. You just need to build the map.
+
+But to do this, the event processor expects all of your state methods to have a
+specific shape. Their method signatures have to look a certain way and their
+if-else structures have to be framed-in just right, otherwise the event
+processor will get lost while it's searching for the correct behavior.
+
+Wouldn't it be nice if the library wrote the methods for you too? Well it can,
+you can use a factory to create state method nodes, then link in event
+callbacks and assign parents at run time. The benefit of such an approach is
+that you can avoid the strangeness of a state method. It will become harder
+for a maintenance developer to accidentally break your statechart by making
+something that looks like an innocuous change. The factory hides the
+topological structure of your state methods behind another layer of
+indirection.
+
+However, if you use this library to write your state methods for you, you are
+placing yet another layer of abstraction between you and your design. A bug
+might be even harder to find than it was before. The nice thing about the
+state methods is that they are easy to understand, they are flat, and you can
+literally see the code and break within it for debugging. The cognitive
+difficulty experienced while trouble shooting a flat state method is much less
+than it would be for something that is auto-generated.
+
+
+.. _towardsthefactoryexample-standard-approach:
+
+Standard Approach to Writing State Methods
+------------------------------------------
+
+.. image:: _static/factory1.svg
+ :target: _static/factory1.pdf
+ :align: center
+
+To create the above diagram we would define three state methods, ``c``, ``c1``
+and ``c2`` and an active object.
+
+.. code-block:: python
+ :emphasize-lines: 42
+
+ import time
+ from miros import spy_on, pp
+ from miros import ActiveObject
+ from miros import signals, Event, return_status
+
+
+ @spy_on
+ def c(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.INIT_SIGNAL):
+ status = chart.trans(c1)
+ elif(e.signal == signals.BB):
+ status = chart.trans(c)
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def c1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.A):
+ status = chart.trans(c1)
+ else:
+ status, chart.temp.fun = return_status.SUPER, c
+ return status
+
+
+ @spy_on
+ def c2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.A):
+ status = chart.trans(c1)
+ else:
+ status, chart.temp.fun = return_status.SUPER, c
+ return status
+
+
+ ao = ActiveObject()
+ ao.start_at(c2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01) # give your active object a moment to respond
+ pp(ao.spy())
+
+An active object has its own thread, so when you want to communicate to it by
+posting an event, you have to give it the briefest opportunity to react.
+This delay is highlighted in the above code.
+
+When the above code is run, it would output this to your terminal:
+
+ .. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:c2',
+ 'SEARCH_FOR_SUPER_SIGNAL:c',
+ 'ENTRY_SIGNAL:c',
+ 'ENTRY_SIGNAL:c2',
+ 'INIT_SIGNAL:c2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:c2',
+ 'SEARCH_FOR_SUPER_SIGNAL:c1',
+ 'SEARCH_FOR_SUPER_SIGNAL:c2',
+ 'EXIT_SIGNAL:c2',
+ 'ENTRY_SIGNAL:c1',
+ 'INIT_SIGNAL:c1',
+ '<- Queued:(0) Deferred:(0)']
+
+We see from the spy log that we had two run to completion events with no
+surprises. Notice that the event processor tried to call the state functions
+with the ``ENTRY_SIGNAL``, ``INIT_SIGNAL`` and ``EXIT_SIGNAL`` as it should
+have, even though our state methods did not handle these events. The handlers
+for these events were left out of the state method examples to keep the code
+compact. This demonstrates that the event processor assumes that a missing
+handler for ``entry``, ``init`` and ``exit`` signals are handled by a state
+method.
+
+.. _towardsthefactoryexample-registering-callbacks-to-specific-events:
+
+Registering Callbacks to Specific Events
+----------------------------------------
+To build our state method code generation we need to create something that is
+common to all state methods. The state method does two different things, it
+responds to events and it returns parent information.
+
+To break this down even more, we can say that it does four things. It asks two
+questions and answers two questions. It asks "How should I respond to the
+events that I care about?" and "Who is my parent?".
+
+Then it answers these questions with information specific to that state method.
+To make something common across all state methods we can ask the questions but
+we can't answer them. The answers will have to be injected into the state
+methods after they have been created.
+
+To be more specific a general state method could look something like this:
+
+.. code-block:: python
+ :emphasize-lines: 4-6, 8-11
+
+ @spy_on
+ def general_state_method(chart, e):
+
+ # How should I respond to the events that I care about?
+ with chart.signal_callback(e, general_state_method) as fn:
+ status = fn(chart, e)
+
+ # Who is my parent?
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+We see that the chart argument provides different context managers,
+``signal_callback`` and ``parent_callback``. It is within these context
+managers that the answers are made.
+
+To inject the information into the chart
+object so that these context managers have something to answer with we can use the
+``register_signal_callback`` and the ``register_parent`` of the active object.
+
+Things should become a bit clearer with an example, reconsider our previous design:
+
+.. image:: _static/factory3.svg
+ :target: _static/factory3.pdf
+ :align: center
+
+
+.. code-block:: python
+ :emphasize-lines: 4, 16, 28
+
+ @spy_on
+ def tc(chart, e):
+
+ with chart.signal_callback(e, tc) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ @spy_on
+ def tc1(chart, e):
+
+ with chart.signal_callback(e, tc1) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ @spy_on
+ def tc2(chart, e):
+
+ with chart.signal_callback(e, tc2) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+To distinguish these state methods from the previous ones we pre-pend their names
+with `t` which stands for template.
+
+These state methods almost look identical, the highlighted lines spell out how
+they are different; the ``signal_callback`` context manager is using the state
+method's name to get its information. Other than that it hardly seems worth
+writing out the code three times.
+
+Now we have to give it the information required to perform the actions we want,
+first we define some callback methods, then we describe how we want our state
+methods to call them.
+
+.. code-block:: python
+ :emphasize-lines: 1-11, 13, 15-31
+
+ def trans_to_tc(chart, e):
+ return chart.trans(tc)
+
+ def trans_to_tc1(chart, e):
+ return chart.trans(tc1)
+
+ def trans_to_tc2(chart, e):
+ return chart.trans(tc2)
+
+ def do_nothing(chart, e):
+ return return_status.HANDLED
+
+ ao = ActiveObject()
+
+ ao.register_signal_callback(tc, signals.BB, trans_to_tc)
+ ao.register_signal_callback(tc, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc, signals.INIT_SIGNAL, trans_to_tc1)
+ ao.register_parent(tc, ao.top)
+
+ ao.register_signal_callback(tc1, signals.A, trans_to_tc2)
+ ao.register_signal_callback(tc1, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc1, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc1, signals.INIT_SIGNAL, do_nothing)
+ ao.register_parent(tc1, tc)
+
+ ao.register_signal_callback(tc2, signals.A, trans_to_tc1)
+ ao.register_signal_callback(tc2, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc2, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc2, signals.INIT_SIGNAL, do_nothing)
+ ao.register_parent(tc2, tc)
+
+In the first highlighted block we create four different callback methods. They
+have the same method signature as a state method and they work exactly as they
+would if they were defined within a state method.
+
+The second block is just an instantiation of an active object, it has the event
+processor and it also provides a means to register callback methods for events
+and to register a parent state.
+
+The next block shows how are three state methods are given their information.
+For instance, the event ``BB`` will cause state ``tc`` to transition to itself.
+
+If we run this code like we did in our previous example we would expect to it
+behave the same:
+
+.. code-block:: python
+
+ ao.start_at(tc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01) # give your active object a moment to respond
+ pp(ao.spy())
+
+If we ran this code, we would see:
+
+ .. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc',
+ 'ENTRY_SIGNAL:tc',
+ 'ENTRY_SIGNAL:tc2',
+ 'INIT_SIGNAL:tc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:tc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc2',
+ 'EXIT_SIGNAL:tc2',
+ 'ENTRY_SIGNAL:tc1',
+ 'INIT_SIGNAL:tc1',
+ '<- Queued:(0) Deferred:(0)']
+
+.. _towardsthefactoryexample-registering-a-parent-to-a-state-method:
+
+Creating a Statechart Using Templates
+-------------------------------------
+We pretty much wrote the same method three times in a row in our :ref:`last
+example`.
+Wouldn't it be nice if something could write the thing for us?
+
+This is exactly what the ``miros.hsm.state_method_template`` does.
+
+It writes the template code within another function, then copies it so that
+this function result is unique in memory, then it renames it and then decorates
+it with some instrumentation.
+
+.. code-block:: python
+
+ from miros import spy_on
+
+ def state_method_template(name):
+
+ def base_state_method(chart, e):
+
+ with chart.signal_callback(e, name) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback(name) as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ resulting_function = copy(base_state_method)
+ resulting_function.__name__ = name
+ resulting_function = spy_on(resulting_function)
+ return resulting_function
+
+With this method we can automatically write our state methods then register
+event callbacks and parent states.
+
+Let's re-create our example, this time using this ``state_method_template``
+method:
+
+.. image:: _static/factory4.svg
+ :target: _static/factory4.pdf
+ :align: center
+
+.. code-block:: python
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ # create the states
+ fc = state_method_template('fc')
+ fc1 = state_method_template('fc1')
+ fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ ao.register_parent(fc2, fc)
+
+ # start up the active object and watch what is does
+ ao.start_at(fc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(ao.spy())
+
+This is a much more compact version of our map. I removed the registration of
+signals that weren't being used by the design, but more importantly I used the
+``state_method_template`` to create the state methods that could have
+information added to them with the active object registration methods.
+
+The output from this program is:
+
+.. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'EXIT_SIGNAL:fc2',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)']
+
+Which is the expected behavior.
+
+.. _towardsthefactoryexample-using-the-factory-class:
+
+Using the Factory Class
+-----------------------
+The ``active_object`` module's Factory class provides a syntax which is similar to
+the previous miros version. It has the ``create``, ``catch`` and ``nest``
+methods, but it also extends the other API with ``to_method`` and ``to_code``.
+
+The Factory class wraps the ``register_signal_callback`` and
+``register_parent`` described in the :ref:`previous
+section`
+making syntax that is a bit more concise.
+
+.. image:: _static/factory5.svg
+ :target: _static/factory5.pdf
+ :align: center
+
+Here is how you could implement this statechart with the ``Factory`` class:
+
+.. code-block:: python
+ :emphasize-lines: 15
+ :linenos:
+
+ from miros import ActiveObject
+ from miros import signals, Event, return_status
+ from miros import Factory
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ chart = Factory('factory_class_example')
+
+ fc = chart.create(state='fc'). \
+ catch(signal=signals.B, handler=trans_to_fc). \
+ catch(signal=signals.INIT_SIGNAL, handler=trans_to_fc1). \
+ to_method()
+
+ fc1 = chart.create(state='fc1'). \
+ catch(signal=signals.A, handler=trans_to_fc2). \
+ to_method()
+
+ fc2 = chart.create(state='fc2'). \
+ catch(signal=signals.A, handler=trans_to_fc1). \
+ to_method()
+
+ chart.nest(fc, parent=None). \
+ nest(fc1, parent=fc). \
+ nest(fc2, parent=fc)
+
+ chart.start_at(fc)
+ chart.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(chart.spy())
+
+If we ran the above code we would see the expected behavior:
+
+.. code-block:: python
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'INIT_SIGNAL:fc',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'EXIT_SIGNAL:fc1',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)']
+
+
+.. _towardsthefactoryexample-unwinding-a-factory-state-method:
+
+Unwinding a Factory State Method
+--------------------------------
+State methods made from factories are hard to debug because you can't actually
+see their code. If you find that you have an issue with such a state method, you
+can unwind it into flat code using the ``to_code`` method. This method outputs a
+string that you can use as a hand written state method.
+
+In the following example, I'll show how we can 'unwind' a design.
+
+.. image:: _static/factory4.svg
+ :target: _static/factory4.pdf
+ :align: center
+
+First we repeat the work of the last section:
+
+.. code-block:: python
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ # create the states
+ fc = state_method_template('fc')
+ fc1 = state_method_template('fc1')
+ fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ ao.register_parent(fc2, fc)
+
+The ``fc``, ``fc1`` and ``fc2`` objects contain state methods that were
+generated by the framework and their code is hidden within the ``ao`` object.
+
+Now suppose something were to go wrong with this design? An application
+developer would have to know that there are at least four different places to
+look within the miros framework to understand their state method: the
+registration functions, the context managers and in the actual template
+generation function. That would be a lot to keep in their head while they were
+also trying to wrestle with their own design problem.
+
+Instead, they could use the ``to_code`` method, copy the result and write it
+back into the design as flat state methods. In this way they could focus their
+entire attention on their own issue. Here is how they could do it:
+
+.. code-block:: python
+
+ print(ao.to_code(fc))
+ print(ao.to_code(fc1))
+ print(ao.to_code(fc2))
+
+This would output the following:
+
+.. code-block:: python
+
+ @spy_on
+ def fc(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.BB):
+ status = trans_to_fc(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def fc1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc2(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+ @spy_on
+ def fc2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+They could copy these methods and re-write their original code as this, making
+sure that the comment out all of the factory code:
+
+.. code-block:: python
+ :emphasize-lines: 11-24,27-40,43-56, 58-61, 66-69,71-74,76-78
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ @spy_on
+ def fc(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.BB):
+ status = trans_to_fc(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def fc1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc2(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+ @spy_on
+ def fc2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+ # create the states
+ # fc = state_method_template('fc')
+ # fc1 = state_method_template('fc1')
+ # fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ # ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ # ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ # ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ # ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ # ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ # ao.register_parent(fc2, fc)
+
+ # start up the active object and watch what it does
+ ao.start_at(fc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(ao.spy())
+
+The highlighted sections identify all of the changes to the design. New
+flattened state methods were added and the old factory code was commented out.
+If we run this code, we see that it behaves properly:
+
+.. code-block:: python
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'EXIT_SIGNAL:fc2',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)']
+
+Metaprogramming is easy on the person who first writes the code and very hard
+on those that have to maintain or extend the design. Like anything else,
+whether it should be done or not is dependent upon the engineering trade offs.
+
+:ref:`back to examples `
diff --git a/docs/_images/state_recipe_15.svg b/docs/_images/state_recipe_15.svg
index f098a2c..a5e01f0 100644
--- a/docs/_images/state_recipe_15.svg
+++ b/docs/_images/state_recipe_15.svg
@@ -1,7 +1,7 @@
-`_. If you want a very solid
understanding about Harel formalism as it relates to UML, go to the source and
read `Practical UML Statecharts in C/C++, 2nd Edition
-`_ by Miro
-Samek.
+`_ by Dr.
+Miro Samek.
But do you need to read these books before you use UML? No, because we are not
going to treat UML as a formal computer language with mathematical semantics. We
will use UML as something to sketch with.
+The formal language we will use is Python.
+
+This section should give you enough information so that you can make your own
+pictures.
+
*Software modelers depend on and use engineering analogies but often fail to
- understand them. Engineers realize that the models aren't the product; they're
- abstractions of the product. In fact, in most cases, the models are only
- partial abstractions of the product, used to hightlight aspects that the
- engineer should know about the product. The term
- 'executable specification' is an oxymoron -- if the specification were truly executable, it would
+ understand them. Engineers realize that the models aren't the product;
+ they're abstractions of the product. In fact, in most cases, the models are
+ only partial abstractions of the product, used to highlight aspects that the
+ engineer should know about the product. The term 'executable specification'
+ is an oxymoron -- if the specification were truly executable, it would
actually be "the thing". Otherwise, it would merely model "the thing," which
by definition is partial and incomplete.*
-- Dave Thomas
-
-The formal language we will use is Python.
-
-This section should give you enough information so that you can make your own
-pictures.
-
.. _reading_diagrams-install-drawing-software:
Install drawing software
@@ -99,7 +98,7 @@ If you don't have a UML drawing package, go and get one.
Install `UMLet `_.
If you would like to use my pallets, remove the ``palettes`` folder from the
- ``UMLet`` directory, then naviage to that directory in your shell and type:
+ ``UMLet`` directory, then navigate to that directory in your shell and type:
.. code-block:: bash
@@ -113,6 +112,8 @@ The Most Important Rule in UML
**You don't have to draw everything on your picture.**
+Sometimes less is more.
+
.. _reading_diagrams-classes:
Classes
@@ -236,6 +237,13 @@ If you are going to inherit ask yourself if the "is-a", or "is-an", relationship
holds true when you use the two class names in a sentence. "The ToasterOven
class is an ActiveObject"; yes, that makes sense. Ok, I'll use inheritance.
+.. note::
+
+ Technically speaking, you `can't draw static inheritance
+ diagrams`_ when you use Python.
+ It is the child class that determines what ``super`` means, because the MRO
+ is determined dynamically using a process called linearization.
+
If you want all of the states of your statechart to react the same when they see
a specific event, use the :ref:`ultimate hook pattern `.
This gives you all of the benefits of inheritance while still having debuggable
diff --git a/docs/_sources/recipes.rst.txt b/docs/_sources/recipes.rst.txt
index 4dc329b..3a5fae3 100644
--- a/docs/_sources/recipes.rst.txt
+++ b/docs/_sources/recipes.rst.txt
@@ -22,7 +22,9 @@ Demonstration of Capabilities
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In this section I'll show you how you can use the miros library by layering more
-and more of its features into a simple program.
+and more of its features into a simple program. This program will be arbitrary,
+it serves no purpose other than to show how to do the common things you will
+want to do when you build your own systems.
.. contents::
:local:
@@ -57,7 +59,7 @@ interplay is a Hierarchical State Machine (HSM) behavior which follows the Harel
Formalism (picture-to-behavior rules).
Now that we understand a bit of theory and how the miros abstraction works,
-let's look at some examples.
+let's write some code.
.. _recipes-minimal-viable-states:
@@ -2291,340 +2293,313 @@ inner_state about 1 second after the middle_state was entered.
Creating thread-safe class Attributes
-------------------------------------
+If you build a statechart using miros your program is multithreaded. This means
+that if you would like to access the same variable across two threads, you need
+to lock it so that one thread doesn't write to it while another thread is using
+it.
-..
- Creating thread-safe class Attributes
- -------------------------------------
- A statechart is running in a separate thread from our main program; so how do we
- reach into it and read/write a variable? We can't assume that it's thread
- won't be halfway through changing the variable we want to read/write at the moment we
- are trying to access it.
-
- To solve this problem we can use a thread safe queue. If we use the
- ``collections.deque`` from the Python standard library, we can build a little ring
- buffer. The statechart can post information to it, and the main thread can
- read information from it. If we wrap the deque in a ``@property``, our exposed
- variable will just look like an attribute from outside of the class.
-
- Here is an example design of where we turn the ``times_in_inner`` attribute into a
- thread-safe property.
-
- .. image:: _static/state_recipe_15.svg
- :target: _static/state_recipe_15.pdf
- :align: center
-
- There is no UML drawing syntax for creating a Python property, so I just add a
- comment on the diagram after the ``times_in_inner`` attribute about what it
- really is.
+Here is an example design of where we turn the ``times_in_inner`` attribute into a
+thread-safe property using the ``ThreadSafeAttributes`` class (available in
+miros >= 4.1.3).
- We can see how to make the ``times_in_inner`` thread safe attribute below (see
- the highlighted code):
-
- .. code-block:: python
- :emphasize-lines: 25-27, 81-83, 85-87, 153, 209, 210
+.. image:: _static/state_recipe_15.svg
+ :target: _static/state_recipe_15.pdf
+ :align: center
+
+.. note::
+
+ There is no UML drawing syntax for describing an attribute wrapped by a
+ property. There is no UML diagram to show a thread lock, or how multiple
+ inheritance works through `linearization of parent classes
+ `_ using Python ``super()``.
+ Our UML is just a sketch, so we make a note that the ``times_in_inner``
+ is a thread safe attribute and move on.
+
+The ``ThreadSafeAttributes`` class tries to protect you from race conditions by
+inspecting the line of code where the ``times_in_inner`` variable is used and
+wrap it within a thread lock. The ``ThreadSafeAttributes`` is :ref:`limited in
+it's capabilities `, but it will
+lock the non-atomic ``+=`` operation seen below:
+
+.. code-block:: python
+ :emphasize-lines: 11, 15, 143, 199, 200
- # simple_state_15.py
- import re
- import time
- import logging
- from functools import partial
- from collections import deque
-
- from miros import Event
- from miros import signals
- from miros import Factory
- from miros import return_status
-
- class F1(Factory):
-
- def __init__(self, name, log_file_name=None,
- live_trace=None, live_spy=None):
-
- super().__init__(name)
-
- self.live_trace = \
- False if live_trace == None else live_trace
- self.live_spy = \
- False if live_spy == None else live_spy
-
- # set up a thread safe ring buffer of size 1
- self._times_in_inner = deque(maxlen=1)
- self._times_in_inner.append(0)
-
- self.log_file_name = \
- 'simple_state_15.log' if log_file_name == None else log_file_name
-
- # clear our log every time we run this program
- with open(self.log_file_name, "w") as fp:
- fp.write("")
-
- logging.basicConfig(
- format='%(asctime)s %(levelname)s:%(message)s',
- filename=self.log_file_name,
- level=logging.DEBUG)
-
- self.register_live_spy_callback(partial(self.spy_callback))
- self.register_live_trace_callback(partial(self.trace_callback))
-
- self.outer_state = self.create(state="outer_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.outer_state_entry_signal). \
- catch(signal=signals.INIT_SIGNAL,
- handler=self.outer_state_init_signal). \
- catch(signal=signals.Hook,
- handler=self.outer_state_hook). \
- catch(signal=signals.Send_Broadcast, \
- handler=self.outer_state_send_broadcast). \
- catch(signal=signals.BROADCAST, \
- handler=self.outer_state_broadcast). \
- catch(signal=signals.Reset,
- handler=self.outer_state_reset). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.outer_state_exit_signal). \
- to_method()
-
- self.middle_state = self.create(state="middle_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.middle_state_entry_signal). \
- catch(signal=signals.Ready,
- handler=self.middle_state_ready). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.middle_state_exit_signal). \
- to_method()
-
- self.inner_state = self.create(state="inner_state"). \
- catch(signal=signals.ENTRY_SIGNAL,
- handler=self.inner_state_entry_signal). \
- catch(signal=signals.EXIT_SIGNAL,
- handler=self.inner_state_exit_signal). \
- to_method()
-
- self.nest(self.outer_state, parent=None). \
- nest(self.middle_state, parent=self.outer_state). \
- nest(self.inner_state, parent=self.middle_state)
-
- @property
- def times_in_inner(self):
- return self._times_in_inner[-1]
-
- @times_in_inner.setter
- def times_in_inner(self, value):
- self._times_in_inner.append(value)
-
- def trace_callback(self, trace):
- '''trace without datetime-stamp'''
- trace_without_datetime = re.search(r'(\[.+\]) (\[.+\].+)', trace).group(2)
- logging.debug("T: " + trace_without_datetime)
-
- def spy_callback(self, spy):
- '''spy with machine name pre-pended'''
- logging.debug("S: [{}] {}".format(self.name, spy))
-
- def outer_state_entry_signal(self, e):
- self.subscribe(Event(signal=signals.BROADCAST))
- self.scribble("hello from outer_state")
- status = return_status.HANDLED
- return status
-
- def outer_state_init_signal(self, e):
- self.scribble("init")
- status = self.trans(self.middle_state)
- return status
-
- def outer_state_hook(self, e):
- status = return_status.HANDLED
- self.scribble("run some code, but don't transition")
- return status
-
- def outer_state_send_broadcast(self, e):
- status = return_status.HANDLED
- self.publish(Event(signal=signals.BROADCAST))
- return status
-
- def outer_state_broadcast(self, e):
- status = return_status.HANDLED
- self.scribble("received broadcast")
- return status
-
- def outer_state_reset(self, e):
- status = self.trans(self.outer_state)
- return status
-
- def outer_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting the outer_state")
- return status
-
- def middle_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.scribble("arming one-shot")
- self.post_fifo(Event(signal=signals.Ready),
- times=1,
- period=1.0,
- deferred=True)
- return status
-
- def middle_state_ready(self, e):
- status = self.trans(self.inner_state)
- return status
-
- def middle_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.cancel_events(Event(signal=signals.Ready))
- return status
-
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.times_in_inner += 1
- self.scribble(
- "hello from inner_state {}".format(self.times_in_inner))
- return status
-
- def inner_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting inner_state")
- return status
-
- class F2(F1):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.scribble("hello from new inner_state")
- return status
-
- def inner_state_exit_signal(self, e):
- status = return_status.HANDLED
- self.scribble("exiting new inner_state")
- return status
-
- if __name__ == '__main__':
-
- f1 = F1(
- "f1",
- live_trace=True,
- live_spy=True,
- )
-
- f2 = F2(
- "f2",
- live_trace=True,
- live_spy=True,
- )
-
- f1.start_at(f1.outer_state)
- f1.post_fifo(Event(signal=signals.Hook))
- f1.post_fifo(
- Event(signal=signals.Reset),
+ # simple_state_15.py
+ import re
+ import time
+ import logging
+ from functools import partial
+
+ from miros import Event
+ from miros import signals
+ from miros import Factory
+ from miros import return_status
+ from miros import ThreadSafeAttributes
+
+ class F1(Factory, ThreadSafeAttributes):
+
+ _attributes = ['times_in_inner']
+
+ def __init__(self, name, log_file_name=None,
+ live_trace=None, live_spy=None):
+
+ super().__init__(name)
+
+ self.live_trace = \
+ False if live_trace == None else live_trace
+ self.live_spy = \
+ False if live_spy == None else live_spy
+
+ self.log_file_name = \
+ 'simple_state_15.log' if log_file_name == None else log_file_name
+
+ # clear our log every time we run this program
+ with open(self.log_file_name, "w") as fp:
+ fp.write("")
+
+ logging.basicConfig(
+ format='%(asctime)s %(levelname)s:%(message)s',
+ filename=self.log_file_name,
+ level=logging.DEBUG)
+
+ self.register_live_spy_callback(partial(self.spy_callback))
+ self.register_live_trace_callback(partial(self.trace_callback))
+
+ self.outer_state = self.create(state="outer_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.outer_state_entry_signal). \
+ catch(signal=signals.INIT_SIGNAL,
+ handler=self.outer_state_init_signal). \
+ catch(signal=signals.Hook,
+ handler=self.outer_state_hook). \
+ catch(signal=signals.Send_Broadcast, \
+ handler=self.outer_state_send_broadcast). \
+ catch(signal=signals.BROADCAST, \
+ handler=self.outer_state_broadcast). \
+ catch(signal=signals.Reset,
+ handler=self.outer_state_reset). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.outer_state_exit_signal). \
+ to_method()
+
+ self.middle_state = self.create(state="middle_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.middle_state_entry_signal). \
+ catch(signal=signals.Ready,
+ handler=self.middle_state_ready). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.middle_state_exit_signal). \
+ to_method()
+
+ self.inner_state = self.create(state="inner_state"). \
+ catch(signal=signals.ENTRY_SIGNAL,
+ handler=self.inner_state_entry_signal). \
+ catch(signal=signals.EXIT_SIGNAL,
+ handler=self.inner_state_exit_signal). \
+ to_method()
+
+ self.nest(self.outer_state, parent=None). \
+ nest(self.middle_state, parent=self.outer_state). \
+ nest(self.inner_state, parent=self.middle_state)
+
+ def trace_callback(self, trace):
+ '''trace without datetime-stamp'''
+ trace_without_datetime = re.search(r'(\[.+\]) (\[.+\].+)', trace).group(2)
+ logging.debug("T: " + trace_without_datetime)
+
+ def spy_callback(self, spy):
+ '''spy with machine name pre-pended'''
+ logging.debug("S: [{}] {}".format(self.name, spy))
+
+ def outer_state_entry_signal(self, e):
+ self.subscribe(Event(signal=signals.BROADCAST))
+ self.scribble("hello from outer_state")
+ status = return_status.HANDLED
+ return status
+
+ def outer_state_init_signal(self, e):
+ self.scribble("init")
+ status = self.trans(self.middle_state)
+ return status
+
+ def outer_state_hook(self, e):
+ status = return_status.HANDLED
+ self.scribble("run some code, but don't transition")
+ return status
+
+ def outer_state_send_broadcast(self, e):
+ status = return_status.HANDLED
+ self.publish(Event(signal=signals.BROADCAST))
+ return status
+
+ def outer_state_broadcast(self, e):
+ status = return_status.HANDLED
+ self.scribble("received broadcast")
+ return status
+
+ def outer_state_reset(self, e):
+ status = self.trans(self.outer_state)
+ return status
+
+ def outer_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting the outer_state")
+ return status
+
+ def middle_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("arming one-shot")
+ self.post_fifo(Event(signal=signals.Ready),
times=1,
- period=2.0,
- deferred=True
- )
-
- f2.start_at(f2.inner_state)
- f2.post_fifo(Event(signal=signals.Hook))
- f2.post_fifo(Event(signal=signals.Reset))
- f1.post_fifo(Event(signal=signals.Send_Broadcast))
-
- # delay long enough so we can see how the program behaves in time
- time.sleep(4.00)
-
- # read information from other threads
- print("f1 was in its inner state {} times".format(f1.times_in_inner))
- print("f2 was in its inner state {} times".format(f2.times_in_inner))
-
- Running this program will provide the following output:
-
- .. code-block:: python
-
- f1 was in its inner state 2 times
- f2 was in its inner state 0 times
-
- The f1 statechart properly reports how many times it was in its inner_state.
- The f2 inner_state doesn't write to the ``times_in_inner`` property, so it's
- output only shows how that property was initialized.
-
- Let's look at the property code in isolation from the rest of the statechart:
-
- .. code-block:: python
- :emphasize-lines: 1
- :linenos:
-
- # INITIALIZATION CODE TAKEN FROM __init__
- # set up a thread safe ring buffer of size 1
- self._times_in_inner = deque(maxlen=1)
- self._times_in_inner.append(0)
- # ...
- # PROPERTY methods used to control the deque
- @property
- def times_in_inner(self):
- return self._times_in_inner[-1]
-
- @times_in_inner.setter
- def times_in_inner(self, value):
- self._times_in_inner.append(value)
- # ...
- # CODE FROM WITHIN STATECHART using the property
- def inner_state_entry_signal(self, e):
- status = return_status.HANDLED
- self.times_in_inner += 1
- self.scribble(
- "hello from inner_state {}".format(self.times_in_inner))
- return status
- # ...
- # CODE OUTSIDE OF STATECHART accessing the property
- print("f1 was in its inner state {} times".format(f1.times_in_inner))
-
- The initialization code on lines 3-4 of this listing, creates a private deque
- ring-buffer which can hold one item, then pushes a zero into this queue. Since
- our ``_time_in_inner`` deque is a ring buffer of size 1, when we ``append`` new
- information into it, it's old information is shifted out of the ring (deleted).
-
- We see this kind of ``append`` taking place in the ``times_in_inner`` setter
- method on lines 12 to 13. The value is shifted into the deque and the old information
- is pushed out. This is a thread safe activity; if more than one thread is
- accessing this method at once, they don't both get to perform the action at the
- same time. One will get its turn, then the other will get its turn.
-
- The ``times_in_inner`` getter method described in lines 7-9 of the listing
- shows us how we can access our information from within or outside of our
- statechart's thread. We only read the latest member of the deque. Since our
- deque is of size one, there is only one thing to read in it anyway.
-
- We can see how this property is used within the statechart's thread on line 18. The
- ``self.times_in_inner += 1`` calls the getter method 8-9, adds one to the result
- then calls the setter method (12-13) which appends the result into the deque,
- shifting the old information out.
-
- We can see how the ``times_in_inner`` property is accessed outside of the
- statechart thread on line 24. The main thread accesses the getter method 8-9, and
- reports its returned value in a print statement.
-
- As of miros 4.1.3, you could create the same thread-safe-attribute like
- this:
-
- .. code-block:: python
-
- from miros import Factory
- # ...
- from miros import ThreadSafeAttributes
-
- class F1(Factory, ThreadSafeAttributes):
- _attribute = ['times_in_inner']
-
- def __init__(self, name, log_file_name=None,
- live_trace=None, live_spy=None):
- # ...
-
- The ThreadSafeAttributes class contains code which automatically makes the
- deque, initializes and wraps the deque within a property. To build such
- attributes, we place the thread-safe-attribute names in a list and assign it to
- ``_attributes``, as seen above. If you would like to read more about this,
- consider:
+ period=1.0,
+ deferred=True)
+ return status
+
+ def middle_state_ready(self, e):
+ status = self.trans(self.inner_state)
+ return status
+
+ def middle_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.cancel_events(Event(signal=signals.Ready))
+ return status
+
+ def inner_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.times_in_inner += 1
+ self.scribble(
+ "hello from inner_state {}".format(self.times_in_inner))
+ return status
+
+ def inner_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting inner_state")
+ return status
+
+ class F2(F1):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ def inner_state_entry_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("hello from new inner_state")
+ return status
+
+ def inner_state_exit_signal(self, e):
+ status = return_status.HANDLED
+ self.scribble("exiting new inner_state")
+ return status
+
+ if __name__ == '__main__':
+
+ f1 = F1(
+ "f1",
+ live_trace=True,
+ live_spy=True,
+ )
+
+ f2 = F2(
+ "f2",
+ live_trace=True,
+ live_spy=True,
+ )
+
+ f1.start_at(f1.outer_state)
+ f1.post_fifo(Event(signal=signals.Hook))
+ f1.post_fifo(
+ Event(signal=signals.Reset),
+ times=1,
+ period=2.0,
+ deferred=True
+ )
+
+ f2.start_at(f2.inner_state)
+ f2.post_fifo(Event(signal=signals.Hook))
+ f2.post_fifo(Event(signal=signals.Reset))
+ f1.post_fifo(Event(signal=signals.Send_Broadcast))
+
+ # delay long enough so we can see how the program behaves in time
+ time.sleep(4.00)
+
+ # read information from other threads
+ print("f1 was in its inner state {} times".format(f1.times_in_inner))
+ print("f2 was in its inner state {} times".format(f2.times_in_inner))
+
+So where is the lock?
+
+It's hidden from view. The ``times_in_inner`` is a kind of ``@property`` and
+the variable that holds its information is protected by another hidden variable
+that is the lock.
+
+Running this program will provide the following output:
+
+.. code-block:: python
- * :ref:`Sharing attributes between threads (ActiveObjects) `
- * :ref:`Sharing attributes between threads (Factories)`
+ f1 was in its inner state 2 times
+ f2 was in its inner state 0 times
+
+The f1 statechart properly reports how many times it was in its inner_state.
+The f2 inner_state doesn't write to the ``times_in_inner`` property, so it's
+output only shows how that property was initialized.
+
+Let's look at the thread safe code in isolation:
+
+.. code-block:: python
+
+ from miros import Factory
+ # ...
+ from miros import ThreadSafeAttributes
+
+ class F1(Factory, ThreadSafeAttributes):
+ _attribute = ['times_in_inner'] # Uses a metaclass to make the
+ # times_in_inner property, with its
+ # protecting lock
+
+ def __init__(self, name, log_file_name=None,
+ live_trace=None, live_spy=None):
+ # ...
+ self.times_in_inner = 0
+
+ def some_state(self, e):
+ # ..
+ # Inside of the state thread small operations on the times_in_inner
+ # attribute can use used in a thread safe way
+ print(self.times_in_inner) # safe
+ a = self.times_in_inner # safe
+ self.times_in_inner = 1 # safe
+ self.times_in_inner += 1 # safe
+ self.times_in_inner += 2 * self.times_in_inner # NOT safe
+ self.times_in_inner = self.times_in_inner + 1 # NOT safe
+ self.times_in_inner = 2 * self.times_in_inner # NOT safe
+
+The ``ThreadSafeAttributes`` class behaves like a macro, wrapping the getting
+and setting of the thread safe attribute within a thread lock. It also wraps
+simple, ``+=``, ``-=``, ..., ``<<=`` statements within a lock. But that's it.
+It can't protect other types of statements from race conditions. If you need to
+use your thread safe attribute to perform more complex operations, use a
+temporary variable and copy the results into the thread safe attribute when you
+are done.
+
+Better yet, share information using published events. But, the thread safe
+attributes feature is very useful when you are sharing information between a
+statechart and a thread which is not a statechart, like main.
+
+.. note::
+
+ Accessing a thread safe attribute will be very slow. In the background
+ the ``ThreadSafeAttributes`` uses a metaclass, and the descriptor protocol.
+ Within the descriptor protocol it uses the ``inspect`` library to read the
+ previous line of code and compares it to a regular expression. Keep this in
+ mind when you use this feature.
+
+* :ref:`Sharing attributes between threads (ActiveObjects) `
+* :ref:`Sharing attributes between threads (Factories)`
+
+If you have gotten this far, you have a good handle on how to use this library
+and all of its features. But you can take it to another level though. Your
+statecharts can send encrypted messages to one another and act in concert while
+running on different machines. To see how to do this, look at the
+`miros-rabbitmq `_ library.
----
diff --git a/docs/_sources/thread_safe_attributes.rst.txt b/docs/_sources/thread_safe_attributes.rst.txt
index a3f8f49..06d9fc2 100644
--- a/docs/_sources/thread_safe_attributes.rst.txt
+++ b/docs/_sources/thread_safe_attributes.rst.txt
@@ -1,521 +1,549 @@
-.. _thread_safe_attributes-thread-safe-attributes:
-
-Thread Safe Attributes
-======================
-
-If you use a statechart, your program is multi-threaded.
-
-Sometimes, you will want to access an attribute of your statechart from another
-thread, like the main part of your program. When you do this, you are trying to
-access memory that could be changed in one thread while it is being read in by
-another thread.
-
-To see why this is an issue imagine using a calculator to solve a simple math
-problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
-following equation:
-
-.. code-block:: python
-
- b = a*cos(0.45) + 3*a^1.2
-
-Seems simple enough. Suppose you pick a straight-forward strategy:
-
- * mark down the value of ``a`` on a piece of paper so you can reference it as you work
- * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
- * then add these results together to find ``b``
-
-But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
-paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
-your desk. You don't notice it. When you get to the ``3*a^1.2`` part of the
-calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
-
-This is called a **race condition**. Here our ``a`` variable was shared between
-two threads, you and the other person. When you program with multiple
-concurrent processes/threads and you share memory, you are exposed to this kind
-of problem.
-
-A simple way to avoid such a situation is to not share the temporary paper in
-the first place. Do not use shared attributes.
-
-Another way to deal with it is to have one thread change a shared attribute and
-have the other thread read the shared attribute. But, this will require that
-maintenance developers understand there are hidden rules in your codebase;
-they could innocently change something an introduce extremely subtle bugs.
-
-Typically, shared variables are protected using thread locks. A lock is a flag
-which works across multiple threads. You can lock the object for reading and
-writing while you use it. In our example, we would lock ``a`` in its ``0.35``
-state while calculating both sub-parts of our problem then unlock it when we are
-done. The other process would wait until the thread-lock cleared, then
-they would change the value of ``a`` to ``0.3`` and do their own work. So,
-there is a cost, you block one thread while waiting for the other to work, and
-you have to share lock variables across all of your threads. It is easy to
-screw this up, and it is tough to test for race conditions.
-
-But why is it hard to test for race conditions? As of Python 3, a thread will
-run for 15 milliseconds before Python passes control to another thread. Most of
-the time, the common memory that is used by both threads will work as you expect
-it will. Infrequently a thread switch will occur midway through a non-atomic
-operation, where some shared value is to be changed by the other
-thread. After this unlikely event, your thread will re-gain control and finish
-its calculation producing the wrong answer.
-
-These kinds of bugs are more probabilistic in nature, than deterministic;
-Python's access to the system clock is jittery. The timing between two Python
-threads will never be the same for every two runs of the program (it's like
-playing a slot machine) so, it will be hard for you to reproduce your issue.
-
-The miros library accepts that people will want to access a statechart's
-internal attributes from the outside. Significant efforts have been made to
-make this kind of activity easy for you to do in a "thread-safe" manner. The
-``ThreadSafeAttributes`` class was constructed to eat the complexity of making
-thread-safe attributes by wrapping "getting" (use of the ".") and "setting"
-operations (use of the "=") within thread-safe locks. In addition to this, the
-non-atomic "+=", "-=" ... "//=" statements using thread-safe attributes were
-also wrapped within locks. For more complex situations, the
-thread-safety features provided by the ``ThreadSafeAttributes`` class can be
-used get to get the thread lock explicitly.
-
-I will introduce these ideas gradually through a set of examples. Let's
-begin by looking at four interacting threads (possible race conditions are
-highlighted):
-
-.. code-block:: python
- :emphasize-lines: 18, 19, 31, 32
- :linenos:
-
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- from miros import ThreadSafeAttributes
-
- class GetLock1(ThreadSafeAttributes):
- _attributes = ['thread_safe_attr_1']
-
- def __init__(self, evt):
- '''running in main thread'''
- self.evt = evt
- self.thread_safe_attr_1 = 0
-
- def thread_method_1(self):
- '''running in th1 thread'''
- while(self.evt.is_set()):
- self.thread_safe_attr_1 += 1
- print("th1: ", self.thread_safe_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running in main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running in th1 thread'''
- while(self.evt.is_set()):
- self.gl1.thread_safe_attr_1 -= 1
- print("th2: ", self.gl1.thread_safe_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running in main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running in killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- # main thread:
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='killer', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-The ``GetLock1`` class inherits from the ``ThreadSafeAttributes`` class, which
-uses a metaclass to give it access to the following syntax (seen on line 8 of
-the above example):
-
-.. code-block:: python
-
- _attributes = ['thread_safe_attr_1']
-
-The ``ThreadSafeAttributes`` class tries to protect you. When we write the
-``_attributes = ['thread_safe_attr_1']`` syntax, ``ThreadSafeAttributes`` creates
-a set of hidden attributes, which are wrapped inside of a `descriptor protocol
-`_ (think @property). One of
-the hidden attributes, `_lock` is a `threading.RLock
-`_. It is
-used to lock and unlock itself around accesses to the other hidden attribute
-`_value`. Essentially this means that this code:
-
-.. code-block:: python
-
- gl1.thread_safe_attr_1
- gl1.thread_safe_attr_1 = 1
-
-... would turn into something like this before it is run:
-
-.. code-block:: python
-
- with gl1._lock:
- gl1.thread_safe_attr_1
-
- with gl1._lock:
- gl1.thread_safe_attr_1 = 1
-
-
-.. note::
-
- A lot of Python libraries provide features to change simple syntax into more
- complex and specific syntax prior to having it run. If this library was
- written in c, this kind of work would be done inside of a macro, and the
- preprocessor would create custom c-code before it was compiled into an
- executable.
-
-The ``ThreadSafeAttributes`` class also tries to protect your code from race
-conditions introduced by non-atomic ``+=`` statements acting on shared
-attributes:
-
-.. code-block:: python
-
- gl1.thread_safe_attr_1 += 1
-
-When using the ``ThreadSafeAttributes`` class the above code turns into something like this:
-
-.. code-block:: python
-
- with gl1._lock:
- temp = gl1.thread_safe_attr_1
- temp = temp + 1
- gl1.thread_safe_attr_1 = temp
-
-So the ``ThreadSafeAttributes`` class protects calls to the
-seemingly-innocuous-looking, yet dangerous, "+=", "-=", ... "//=" family of
-Python calls. They are dangerous because they are not-atomic and can cause race
-conditions if they are applied to attributes shared across threads.
-
-So our example, written without the ``ThreadSafeAttributes`` class, but with the
-same protections would look like this (shared attributes protections
-highlighted):
-
-.. code-block:: python
- :emphasize-lines: 11, 18-21, 33-36
- :linenos:
-
- place code here
- import time
- from threading import RLock
- from threading import Thread
- from threading import Event as ThreadEvent
-
- class GetLock1():
-
- def __init__(self, evt):
- '''running within main thread'''
- self._rlock = RLock()
- self.evt = evt
- self.thread_safe_attr_1 = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- while(self.evt.is_set()):
- with self._rlock:
- self.thread_safe_attr_1 += 1
- with self._rlock:
- print("th1: ", self.thread_safe_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- while(self.evt.is_set()):
- with self.gl1._rlock:
- self.gl1.thread_safe_attr_1 -= 1
- with self.gl1._rlock:
- print("th2: ", self.gl1.thread_safe_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-We haven't looked at any code results yet. Let's run it and see what it does:
-
-.. code-block:: bash
-
- $python thread_safe_attributes_2.py
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th2: -1
- th1: 0
- th1: 1
- th2: 0
-
-We see that the number oscillates about 0. If we remove the time delays at the
-bottom of the thread functions, you will see wild oscillation in this number,
-since one thread by chance will get many more opportunities to run. So you can
-see that it might be hard to reproduce precisely two identical traces of the
-program output.
-
-Ok, now for something scary, let's look at our code without thread-locks (the
-race conditions are highlighted):
-
-.. code-block:: python
- :emphasize-lines: 15, 16, 28, 29
- :linenos:
-
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- class GetLock1():
-
- def __init__(self, evt):
- '''running within main thread'''
- self.evt = evt
- self.thread_race_attr_1 = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- while(self.evt.is_set()):
- self.thread_race_attr_1 += 1
- print("th1: ", self.thread_race_attr_1)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- while(self.evt.is_set()):
- self.gl1.thread_race_attr_1 -= 1
- print("th2: ", self.gl1.thread_race_attr_1)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-I changed the ``thread_safe_attr_1`` name to ``thread_race_attr_1`` to make a
-point. The highlighted code shows where race conditions can occur. If we run
-the code we see:
-
-.. code-block:: bash
-
- python thread_safe_attributes_3_unsafe.py
- th1: 1
- th2: 0
- th1: 1
- th2: 0
- th2: -1
- th1: 0
- th1: 1
- th2: 0
- th1: 1
- th2: 0
-
-Which looks almost exactly the same as the last run. Race conditions are very
-hard to find.
-
-Let's move back to our original example, suppose we absolutely needed
-to run calculations on the ``thread_safe_attr_1`` in more than one thread (which
-I can't see the need for). I'll change the name of ``thread_safe_attr_1`` to
-``a``. The ``ThreadSafeAttributes`` class can not implicitly protect you in such
-situations, but what it can do is give you the lock and you can use it to
-protect your own code (highlighting how to get the lock):
-
-.. code-block:: python
- :emphasize-lines: 18, 34
- :linenos:
-
- import math
- import time
- from threading import Thread
- from threading import Event as ThreadEvent
-
- from miros import ThreadSafeAttributes
-
- class GetLock1(ThreadSafeAttributes):
- _attributes = ['a']
-
- def __init__(self, evt):
- '''running within main thread'''
- self.evt = evt
- self.a = 0
-
- def thread_method_1(self):
- '''running within th1 thread'''
- _, _lock = self.a
- while(self.evt.is_set()):
- with _lock:
- self.a = 0.35
- b = self.a * math.cos(0.45) + 3 * self.a ** 1.2
- print("th1: ", b)
- time.sleep(0.020)
-
- class GetLock2():
- def __init__(self, evt, gl1):
- '''running within main thread'''
- self.evt = evt
- self.gl1 = gl1
-
- def thread_method_2(self):
- '''running within th2 thread'''
- _, _lock = self.gl1.a
- while(self.evt.is_set()):
- with _lock:
- self.gl1.a = 0.30
- b = self.gl1.a * math.cos(0.45) + 3 * self.gl1.a ** 1.2
- print("th2: ", b)
- time.sleep(0.020)
-
- class ThreadKiller():
- def __init__(self, evt, count_down):
- '''running within main thread'''
- self.evt = evt
- self.kill_time = count_down
-
- def thread_stopper(self):
- '''running within killer thread'''
- time.sleep(self.kill_time)
- self.evt.clear()
-
- # main thread:
- evt = ThreadEvent()
- evt.set()
-
- gl1 = GetLock1(evt)
- gl2 = GetLock2(evt, gl1=gl1)
- killer = ThreadKiller(evt, count_down=0.1)
-
- threads = []
- threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
- threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
-
- for thread in threads:
- thread.start()
-
- thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
- thread_stopper.start()
- thread_stopper.join()
-
-.. note::
-
- You can download the above code `here
- `_
-
-The lock can be obtained by calling ``_, _lock = ``.
-
-This is a little nasty piece of metaprogramming that could baffle a beginner or
-anyone who looks at the thread safe attribute. Most of the time your thread
-safe attribute acts as an attribute, but other times it acts as an iterable,
-what is going on? It only acts as an interable when proceeded by ``_, _lock``.
-If you use this technique in one of your threads, you must use it in all of your
-threads.
-
-Once again I recommend against performing calculations directly on your shared
-attributes. Instead, copy their variable into a temp, perform a calculation
-then assign the results into them.
-
-.. note::
-
- The ``ThreadSafeAttributes`` feature actually reads the last line of code you
- have written, the behaves differently depending on what you have written. It
- is because of this feature it can release it's lock in what looks like a
- syntactically inconsistent way.
-
-:ref:`back to examples `
+
+ *The best is the enemy of the good.*
+
+ -- Voltaire
+
+.. _thread_safe_attributes-thread-safe-attributes:
+
+Thread Safe Attributes
+======================
+
+If you use a miros statechart, your program is multi-threaded.
+
+Sometimes, you will want to access an attribute of your statechart from another
+thread, like the main part of your program. When you do this, you are trying to
+access memory that could be changed in one thread while it is being read in by
+another thread.
+
+To see why this is an issue imagine using a calculator to solve a simple math
+problem: calculate the value of ``b``, starting with ``a == 0.35``, given the
+following equation:
+
+.. code-block:: python
+
+ b = a*cos(0.45) + 3*a^1.2
+
+Seems simple enough. Suppose you pick a straight-forward strategy:
+
+ * mark down the value of ``a`` on a piece of paper so you can reference it as you work
+ * break the calculation into ``a * cos(0.45)`` and ``3*a*1.2``
+ * then add these results together to find ``b``
+
+But while calculated the ``a*cos(0.45)`` part of the problem, someone grabs your
+paper, changes your temporary value of ``a`` to ``0.3``, then puts it back on
+your desk. You don't notice it. When you get to the ``3*a^1.2`` part of the
+calculation, you use the wrong ``a`` value, so you get the wrong answer for ``b``.
+
+This is called a **race condition**. Here our ``a`` variable was shared between
+two threads, you and the other person. When you program with multiple
+concurrent processes/threads and you share memory, you are exposed to this kind
+of problem.
+
+A simple way to avoid such a situation is to not share the temporary paper in
+the first place. Do not use shared attributes.
+
+Another way to deal with it is to have one thread change a shared attribute and
+have the other thread read the shared attribute. But, this will require that
+maintenance developers understand there are hidden rules in your codebase;
+they could innocently change something an introduce extremely subtle bugs.
+
+Typically, shared variables are protected using thread locks. A lock is a flag
+which works across multiple threads. You can lock the object for reading and
+writing while you use it. In our example, we would lock ``a`` in its ``0.35``
+state while calculating both sub-parts of our problem then unlock it when we are
+done. The other process would wait until the thread-lock cleared, then
+they would change the value of ``a`` to ``0.3`` and do their own work. So,
+there is a cost, you block one thread while waiting for the other to work, and
+you have to share lock variables across all of your threads. It is easy to
+screw this up, and it is tough to test for race conditions.
+
+But why is it hard to test for race conditions? As of Python 3, a thread will
+run for 15 milliseconds before Python passes control to another thread. Most of
+the time, the common memory that is used by both threads will work as you expect
+it will. Infrequently a thread switch will occur midway through a non-atomic
+operation, where some shared value is to be changed by the other
+thread. After this unlikely event, your thread will re-gain control and finish
+its calculation producing the wrong answer.
+
+These kinds of bugs are more probabilistic in nature, than deterministic;
+Python's access to the system clock is jittery. The timing between two Python
+threads will never be the same for every two runs of the program (it's like
+playing a slot machine) so, it will be hard for you to reproduce your issue.
+
+The miros library accepts that people will want to access a statechart's
+internal attributes from the outside. Significant efforts have been made to
+make this kind of activity easy for you to do in a "thread-safe" manner. The
+``ThreadSafeAttributes`` class was constructed to eat the complexity of making
+thread-safe attributes by wrapping "getting" (use of the ".") and "setting"
+operations (use of the "=") within thread-safe locks. In addition to this, the
+non-atomic "+=", "-=" ... "//=" statements using thread-safe attributes were
+also wrapped within locks. For more complex situations, the
+thread-safety features provided by the ``ThreadSafeAttributes`` class can be
+used to get the thread lock explicitly.
+
+I will introduce these ideas gradually through a set of examples. Let's
+begin by looking at four interacting threads (possible race conditions are
+highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 18, 19, 31, 32
+ :linenos:
+
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ from miros import ThreadSafeAttributes
+
+ class GetLock1(ThreadSafeAttributes):
+ _attributes = ['thread_safe_attr_1']
+
+ def __init__(self, evt):
+ '''running in main thread'''
+ self.evt = evt
+ self.thread_safe_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running in th1 thread'''
+ while(self.evt.is_set()):
+ self.thread_safe_attr_1 += 1
+ print("th1: ", self.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running in main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running in th1 thread'''
+ while(self.evt.is_set()):
+ self.gl1.thread_safe_attr_1 -= 1
+ print("th2: ", self.gl1.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running in main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running in killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ # main thread:
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='killer', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+The ``GetLock1`` class inherits from the ``ThreadSafeAttributes`` class, which
+uses a metaclass to give it access to the following syntax (seen on line 8 of
+the above example):
+
+.. code-block:: python
+
+ _attributes = ['thread_safe_attr_1']
+
+The ``ThreadSafeAttributes`` class tries to protect you. When we write the
+``_attributes = ['thread_safe_attr_1']`` syntax, ``ThreadSafeAttributes`` creates
+a set of hidden attributes, which are wrapped inside of a `descriptor protocol
+`_ (think @property). One of
+the hidden attributes, `_lock` is a `threading.RLock
+`_. It is
+used to lock and unlock itself around accesses to the other hidden attribute
+`_value`. Essentially this means that this code:
+
+.. code-block:: python
+
+ gl1.thread_safe_attr_1
+ gl1.thread_safe_attr_1 = 1
+
+... would turn into something like this before it is run:
+
+.. code-block:: python
+
+ with gl1._lock:
+ gl1.thread_safe_attr_1
+
+ with gl1._lock:
+ gl1.thread_safe_attr_1 = 1
+
+
+.. note::
+
+ A lot of Python libraries provide features to change simple syntax into more
+ complex and specific syntax prior to having it run. If this library was
+ written in c, this kind of work would be done inside of a macro, and the
+ preprocessor would create custom c-code before it was compiled into an
+ executable.
+
+The ``ThreadSafeAttributes`` class also tries to protect your code from race
+conditions introduced by non-atomic ``+=`` statements acting on shared
+attributes:
+
+.. code-block:: python
+
+ gl1.thread_safe_attr_1 += 1
+
+When using the ``ThreadSafeAttributes`` class the above code turns into something like this:
+
+.. code-block:: python
+
+ with gl1._lock:
+ temp = gl1.thread_safe_attr_1
+ temp = temp + 1
+ gl1.thread_safe_attr_1 = temp
+
+So the ``ThreadSafeAttributes`` class protects calls to the
+seemingly-innocuous-looking, yet dangerous, "+=", "-=", ... "//=" family of
+Python calls. They are dangerous because they are not-atomic and can cause race
+conditions if they are applied to attributes shared across threads.
+
+So our example, written without the ``ThreadSafeAttributes`` class, but with the
+same protections would look like this (shared attributes protections
+highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 11, 18-21, 33-36
+ :linenos:
+
+ place code here
+ import time
+ from threading import RLock
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ class GetLock1():
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self._rlock = RLock()
+ self.evt = evt
+ self.thread_safe_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ while(self.evt.is_set()):
+ with self._rlock:
+ self.thread_safe_attr_1 += 1
+ with self._rlock:
+ print("th1: ", self.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ while(self.evt.is_set()):
+ with self.gl1._rlock:
+ self.gl1.thread_safe_attr_1 -= 1
+ with self.gl1._rlock:
+ print("th2: ", self.gl1.thread_safe_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+We haven't looked at any code results yet. Let's run it and see what it does:
+
+.. code-block:: bash
+
+ $python thread_safe_attributes_2.py
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th2: -1
+ th1: 0
+ th1: 1
+ th2: 0
+
+We see that the number oscillates about 0. If we remove the time delays at the
+bottom of the thread functions, you will see wild oscillation in this number,
+since one thread by chance will get many more opportunities to run. So you can
+see that it might be hard to reproduce precisely two identical traces of the
+program output.
+
+Ok, now for something scary, let's look at our code without thread-locks (the
+race conditions are highlighted):
+
+.. code-block:: python
+ :emphasize-lines: 15, 16, 28, 29
+ :linenos:
+
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ class GetLock1():
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self.evt = evt
+ self.thread_race_attr_1 = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ while(self.evt.is_set()):
+ self.thread_race_attr_1 += 1
+ print("th1: ", self.thread_race_attr_1)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ while(self.evt.is_set()):
+ self.gl1.thread_race_attr_1 -= 1
+ print("th2: ", self.gl1.thread_race_attr_1)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+I changed the ``thread_safe_attr_1`` name to ``thread_race_attr_1`` to make a
+point. The highlighted code shows where race conditions can occur. If we run
+the code we see:
+
+.. code-block:: bash
+
+ python thread_safe_attributes_3_unsafe.py
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+ th2: -1
+ th1: 0
+ th1: 1
+ th2: 0
+ th1: 1
+ th2: 0
+
+Which looks almost exactly the same as the last run. Race conditions are very
+hard to find.
+
+Let's move back to our original example, suppose we absolutely needed
+to run calculations on the ``thread_safe_attr_1`` in more than one thread (which
+I can't see the need for). I'll change the name of ``thread_safe_attr_1`` to
+``a``. The ``ThreadSafeAttributes`` class can not implicitly protect you in such
+situations, but what it can do is give you the lock and you can use it to
+protect your own code (highlighting how to get the lock):
+
+.. code-block:: python
+ :emphasize-lines: 18, 34
+ :linenos:
+
+ import math
+ import time
+ from threading import Thread
+ from threading import Event as ThreadEvent
+
+ from miros import ThreadSafeAttributes
+
+ class GetLock1(ThreadSafeAttributes):
+ _attributes = ['a']
+
+ def __init__(self, evt):
+ '''running within main thread'''
+ self.evt = evt
+ self.a = 0
+
+ def thread_method_1(self):
+ '''running within th1 thread'''
+ _, _lock = self.a
+ while(self.evt.is_set()):
+ with _lock:
+ self.a = 0.35
+ b = self.a * math.cos(0.45) + 3 * self.a ** 1.2
+ print("th1: ", b)
+ time.sleep(0.020)
+
+ class GetLock2():
+ def __init__(self, evt, gl1):
+ '''running within main thread'''
+ self.evt = evt
+ self.gl1 = gl1
+
+ def thread_method_2(self):
+ '''running within th2 thread'''
+ _, _lock = self.gl1.a
+ while(self.evt.is_set()):
+ with _lock:
+ self.gl1.a = 0.30
+ b = self.gl1.a * math.cos(0.45) + 3 * self.gl1.a ** 1.2
+ print("th2: ", b)
+ time.sleep(0.020)
+
+ class ThreadKiller():
+ def __init__(self, evt, count_down):
+ '''running within main thread'''
+ self.evt = evt
+ self.kill_time = count_down
+
+ def thread_stopper(self):
+ '''running within killer thread'''
+ time.sleep(self.kill_time)
+ self.evt.clear()
+
+ # main thread:
+ evt = ThreadEvent()
+ evt.set()
+
+ gl1 = GetLock1(evt)
+ gl2 = GetLock2(evt, gl1=gl1)
+ killer = ThreadKiller(evt, count_down=0.1)
+
+ threads = []
+ threads.append(Thread(target=gl1.thread_method_1, name='th1', args=()))
+ threads.append(Thread(target=gl2.thread_method_2, name='th2', args=()))
+
+ for thread in threads:
+ thread.start()
+
+ thread_stopper = Thread(target=killer.thread_stopper, name='stopper', args=())
+ thread_stopper.start()
+ thread_stopper.join()
+
+.. note::
+
+ You can download the above code `here
+ `_
+
+The lock can be obtained by calling ``_, _lock = ``.
+
+This nasty little piece of metaprogramming could baffle a beginner or anyone who
+looks at the thread safe attribute: Most of the time your thread-safe attribute
+acts as an attribute, but other times it acts as an iterable, what is going on?
+It only acts as an iterable when proceeded by ``_, _lock``. **If you use this
+technique in one of your threads, you must also explicitly get the lock in all
+other threads that share the attribute.**
+
+This lock-access feature was added for difficult situations, where the client
+code absolutely needs the lock, maybe for advanced database calls or that kind
+of thing.
+
+**I recommend against explicitely getting a lock** and performing calculations
+directly on your shared attributes.
+
+Instead, copy their contents into a local variable (automatically locked) ,
+perform a calculation using local variables, then assign the results back into
+the shared attribute (automatically locked).
+
+In our example, we don't need to use shared attribute at all, so we shouldn't.
+The example was arbitrary, a better way to perform the calculation can be seen
+in the following code listing. If we needed to place the ``0.3`` back into the
+shared-attribute, we can do that, but we keep the shared-attribute out of our
+equation. The equation will use non-shared, thread-safe, local variables which
+are placed on the stack during a thread's context switch.
+
+.. code-block:: python
+
+ # code which doesn't require an explicit lock
+ temp = 0.30
+ b = temp * math.cos(0.45) + 3 * temp ** 1.2
+ print("thr2: ", b)
+ # this code will be implicitly locked by ThreadSafeAttributes
+ self.gl1.a = temp
+
+.. note::
+
+ The ``ThreadSafeAttributes`` feature actually reads the last line of code you
+ have written, the behaves differently depending on what you have written. It
+ is because of this feature it can release it's lock in what looks like a
+ syntactically inconsistent way.
+
+:ref:`back to examples `
diff --git a/docs/_sources/towardsthefactoryexample.rst.txt b/docs/_sources/towardsthefactoryexample.rst.txt
index 521b4d6..c81c83a 100644
--- a/docs/_sources/towardsthefactoryexample.rst.txt
+++ b/docs/_sources/towardsthefactoryexample.rst.txt
@@ -1,786 +1,786 @@
- *You know you are working with clean code when each routine you read turns out to
- be pretty much what you expected. You can call it beautiful code when the code
- also makes it look like the language was made for the problem.*
-
- -- Ward Cunningham
-
-.. _towardsthefactoryexample-towards-a-factory:
-
-Using and Unwinding a Factory
-=============================
-
-.. image:: _static/factory1.svg
- :target: _static/factory1.pdf
- :align: center
-
-.. _towardsthefactoryexample-example-summary:
-
-Example Summary
----------------
-1. :ref:`Standard Approach to Writing State Methods`
-2. :ref:`Registering Callbacks to Specific Events`
-3. :ref:`Creating a Statechart Using Templates`
-4. :ref:`Creating a Statechart Using A Factory`
-5. :ref:`Unwinding a Factory State Method`
-
-.. _towardsthefactoryexample-why-you-would-want-a-factory:
-
-In this example I will walk you through how to hand-code a simple state method
-then show how that same method could be written for you automatically. Then I
-will show how to re-flatten a statechart, so that you can copy this code back
-into your design to make it easier to debug. (Like looking at preprocessor
-results in c).
-
-Why a Factory?
---------------
-The event processor uses the organization of your state methods, who their
-parents are and how they relate to each other as if they defined a complicated
-data structure. These state methods contain your application code too, but
-they `are` the nodes of your graph; they define the topology of your
-statechart.
-
-When you send an event which will cause a transition across multiple states with
-complicated entry/exit/init event triggering to provide the Harel Formalism,
-you don't have to worry about how it is implemented, you just need to ensure
-that you have framed in your state methods with enough structure that the event
-processing algorithm can discover the graph and build out the expected behavior.
-
-This provides the illusion that you are using a completely different type of
-programming language, but it's still all Python. Your state methods are just
-being called over and over again with different arguments.
-
-Miro Samek describes this as "an inversion of control". By using his event
-processing algorithm, you are packing the management complexity of the
-topological search into the bottom part of your software system. By pushing
-this to the bottom, you can focus on writing concise descriptions of how your
-system should behave without concerning yourself with how to implement this
-behavior, the algorithm solves that problem. You just need to build the map.
-
-But to do this, the event processor expects all of your state methods to have a
-specific shape. Their method signatures have to look a certain way and their
-if-else structures have to be framed-in just right, otherwise the event
-processor will get lost while it's searching for the correct behavior.
-
-Wouldn't it be nice if the library wrote the methods for you too? Well it can,
-you can use a factory to create state method nodes, then link in event
-callbacks and assign parents at run time. The benefit of such an approach is
-that you can avoid the strangeness of a state method. It will become harder
-for a maintenance developer to accidentally break your statechart by making
-something that looks like an innocuous change. The factory hides the
-topological structure of your state methods behind another layer of
-indirection.
-
-However, if you use this library to write your state methods for you, you are
-placing yet another layer of abstraction between you and your design. A bug
-might be even harder to find than it was before. The nice thing about the
-state methods is that they are easy to understand, they are flat, and you can
-literally see the code and break within it for debugging. The cognitive
-difficulty experienced while trouble shooting a flat state method is much less
-than it would be for something that is auto-generated.
-
-
-.. _towardsthefactoryexample-standard-approach:
-
-Standard Approach to Writing State Methods
-------------------------------------------
-
-.. image:: _static/factory1.svg
- :target: _static/factory1.pdf
- :align: center
-
-To create the above diagram we would define three state methods, ``c``, ``c1``
-and ``c2`` and an active object.
-
-.. code-block:: python
- :emphasize-lines: 42
-
- import time
- from miros import spy_on, pp
- from miros import ActiveObject
- from miros import signals, Event, return_status
-
-
- @spy_on
- def c(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.INIT_SIGNAL):
- status = chart.trans(c1)
- elif(e.signal == signals.BB):
- status = chart.trans(c)
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def c1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.A):
- status = chart.trans(c1)
- else:
- status, chart.temp.fun = return_status.SUPER, c
- return status
-
-
- @spy_on
- def c2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.A):
- status = chart.trans(c1)
- else:
- status, chart.temp.fun = return_status.SUPER, c
- return status
-
-
- ao = ActiveObject()
- ao.start_at(c2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01) # give your active object a moment to respond
- pp(ao.spy())
-
-An active object has its own thread, so when you want to communicate to it by
-posting an event, you have to give it the briefest opportunity to react.
-This delay is highlighted in the above code.
-
-When the above code is run, it would output this to your terminal:
-
- .. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:c2',
- 'SEARCH_FOR_SUPER_SIGNAL:c',
- 'ENTRY_SIGNAL:c',
- 'ENTRY_SIGNAL:c2',
- 'INIT_SIGNAL:c2',
- '<- Queued:(0) Deferred:(0)',
- 'A:c2',
- 'SEARCH_FOR_SUPER_SIGNAL:c1',
- 'SEARCH_FOR_SUPER_SIGNAL:c2',
- 'EXIT_SIGNAL:c2',
- 'ENTRY_SIGNAL:c1',
- 'INIT_SIGNAL:c1',
- '<- Queued:(0) Deferred:(0)']
-
-We see from the spy log that we had two run to completion events with no
-surprises. Notice that the event processor tried to call the state functions
-with the ``ENTRY_SIGNAL``, ``INIT_SIGNAL`` and ``EXIT_SIGNAL`` as it should
-have, even though our state methods did not handle these events. The handlers
-for these events were left out of the state method examples to keep the code
-compact. This demonstrates that the event processor assumes that a missing
-handler for ``entry``, ``init`` and ``exit`` signals are handled by a state
-method.
-
-.. _towardsthefactoryexample-registering-callbacks-to-specific-events:
-
-Registering Callbacks to Specific Events
-----------------------------------------
-To build our state method code generation we need to create something that is
-common to all state methods. The state method does two different things, it
-responds to events and it returns parent information.
-
-To break this down even more, we can say that it does four things. It asks two
-questions and answers two questions. It asks "How should I respond to the
-events that I care about?" and "Who is my parent?".
-
-Then it answers these questions with information specific to that state method.
-To make something common across all state methods we can ask the questions but
-we can't answer them. The answers will have to be injected into the state
-methods after they have been created.
-
-To be more specific a general state method could look something like this:
-
-.. code-block:: python
- :emphasize-lines: 4-6, 8-11
-
- @spy_on
- def general_state_method(chart, e):
-
- # How should I respond to the events that I care about?
- with chart.signal_callback(e, general_state_method) as fn:
- status = fn(chart, e)
-
- # Who is my parent?
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
-We see that the chart argument provides different context managers,
-``signal_callback`` and ``parent_callback``. It is within these context
-managers that the answers are made.
-
-To inject the information into the chart
-object so that these context managers have something to answer with we can use the
-``register_signal_callback`` and the ``register_parent`` of the active object.
-
-Things should become a bit clearer with an example, reconsider our previous design:
-
-.. image:: _static/factory3.svg
- :target: _static/factory3.pdf
- :align: center
-
-
-.. code-block:: python
- :emphasize-lines: 4, 16, 28
-
- @spy_on
- def tc(chart, e):
-
- with chart.signal_callback(e, tc) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- @spy_on
- def tc1(chart, e):
-
- with chart.signal_callback(e, tc1) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- @spy_on
- def tc2(chart, e):
-
- with chart.signal_callback(e, tc2) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback() as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
-To distinguish these state methods from the previous ones we pre-pend their names
-with `t` which stands for template.
-
-These state methods almost look identical, the highlighted lines spell out how
-they are different; the ``signal_callback`` context manager is using the state
-method's name to get its information. Other than that it hardly seems worth
-writing out the code three times.
-
-Now we have to give it the information required to perform the actions we want,
-first we define some callback methods, then we describe how we want our state
-methods to call them.
-
-.. code-block:: python
- :emphasize-lines: 1-11, 13, 15-31
-
- def trans_to_tc(chart, e):
- return chart.trans(tc)
-
- def trans_to_tc1(chart, e):
- return chart.trans(tc1)
-
- def trans_to_tc2(chart, e):
- return chart.trans(tc2)
-
- def do_nothing(chart, e):
- return return_status.HANDLED
-
- ao = ActiveObject()
-
- ao.register_signal_callback(tc, signals.BB, trans_to_tc)
- ao.register_signal_callback(tc, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc, signals.INIT_SIGNAL, trans_to_tc1)
- ao.register_parent(tc, ao.top)
-
- ao.register_signal_callback(tc1, signals.A, trans_to_tc2)
- ao.register_signal_callback(tc1, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc1, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc1, signals.INIT_SIGNAL, do_nothing)
- ao.register_parent(tc1, tc)
-
- ao.register_signal_callback(tc2, signals.A, trans_to_tc1)
- ao.register_signal_callback(tc2, signals.ENTRY_SIGNAL, do_nothing)
- ao.register_signal_callback(tc2, signals.EXIT_SIGNAL, do_nothing)
- ao.register_signal_callback(tc2, signals.INIT_SIGNAL, do_nothing)
- ao.register_parent(tc2, tc)
-
-In the first highlighted block we create four different callback methods. They
-have the same method signature as a state method and they work exactly as they
-would if they were defined within a state method.
-
-The second block is just an instantiation of an active object, it has the event
-processor and it also provides a means to register callback methods for events
-and to register a parent state.
-
-The next block shows how are three state methods are given their information.
-For instance, the event ``BB`` will cause state ``tc`` to transition to itself.
-
-If we run this code like we did in our previous example we would expect to it
-behave the same:
-
-.. code-block:: python
-
- ao.start_at(tc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01) # give your active object a moment to respond
- pp(ao.spy())
-
-If we ran this code, we would see:
-
- .. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:tc2',
- 'SEARCH_FOR_SUPER_SIGNAL:tc',
- 'ENTRY_SIGNAL:tc',
- 'ENTRY_SIGNAL:tc2',
- 'INIT_SIGNAL:tc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:tc2',
- 'SEARCH_FOR_SUPER_SIGNAL:tc1',
- 'SEARCH_FOR_SUPER_SIGNAL:tc2',
- 'EXIT_SIGNAL:tc2',
- 'ENTRY_SIGNAL:tc1',
- 'INIT_SIGNAL:tc1',
- '<- Queued:(0) Deferred:(0)']
-
-.. _towardsthefactoryexample-registering-a-parent-to-a-state-method:
-
-Creating a Statechart Using Templates
--------------------------------------
-We pretty much wrote the same method three times in a row in our :ref:`last
-example`.
-Wouldn't it be nice if something could write the thing for us?
-
-This is exactly what the ``miros.hsm.state_method_template`` does.
-
-It writes the template code within another function, then copies it so that
-this function result is unique in memory, then it renames it and then decorates
-it with some instrumentation.
-
-.. code-block:: python
-
- from miros import spy_on
-
- def state_method_template(name):
-
- def base_state_method(chart, e):
-
- with chart.signal_callback(e, name) as fn:
- status = fn(chart, e)
-
- if(status == return_status.UNHANDLED):
- with chart.parent_callback(name) as parent:
- status, chart.temp.fun = return_status.SUPER, parent
-
- return status
-
- resulting_function = copy(base_state_method)
- resulting_function.__name__ = name
- resulting_function = spy_on(resulting_function)
- return resulting_function
-
-With this method we can automatically write our state methods then register
-event callbacks and parent states.
-
-Let's re-create our example, this time using this ``state_method_template``
-method:
-
-.. image:: _static/factory4.svg
- :target: _static/factory4.pdf
- :align: center
-
-.. code-block:: python
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- # create the states
- fc = state_method_template('fc')
- fc1 = state_method_template('fc1')
- fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- ao.register_parent(fc2, fc)
-
- # start up the active object and watch what is does
- ao.start_at(fc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(ao.spy())
-
-This is a much more compact version of our map. I removed the registration of
-signals that weren't being used by the design, but more importantly I used the
-``state_method_template`` to create the state methods that could have
-information added to them with the active object registration methods.
-
-The output from this program is:
-
-.. code-block:: python
- :emphasize-lines: 7,14
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'EXIT_SIGNAL:fc2',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)']
-
-Which is the expected behavior.
-
-.. _towardsthefactoryexample-using-the-factory-class:
-
-Using the Factory Class
------------------------
-The ``active_object`` module's Factory class provides a syntax which is similar to
-the previous miros version. It has the ``create``, ``catch`` and ``nest``
-methods, but it also extends the other API with ``to_method`` and ``to_code``.
-
-The Factory class wraps the ``register_signal_callback`` and
-``register_parent`` described in the :ref:`previous
-section`
-making syntax that is a bit more concise.
-
-.. image:: _static/factory5.svg
- :target: _static/factory5.pdf
- :align: center
-
-Here is how you could implement this statechart with the ``Factory`` class:
-
-.. code-block:: python
- :emphasize-lines: 15
- :linenos:
-
- from miros import ActiveObject
- from miros import signals, Event, return_status
- from miros import Factory
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- chart = Factory('factory_class_example')
-
- fc = chart.create(state='fc'). \
- catch(signal=signals.B, handler=trans_to_fc). \
- catch(signal=signals.INIT_SIGNAL, handler=trans_to_fc1). \
- to_method()
-
- fc1 = chart.create(state='fc1'). \
- catch(signal=signals.A, handler=trans_to_fc2). \
- to_method()
-
- fc2 = chart.create(state='fc2'). \
- catch(signal=signals.A, handler=trans_to_fc1). \
- to_method()
-
- chart.nest(fc, parent=None). \
- nest(fc1, parent=fc). \
- nest(fc2, parent=fc)
-
- chart.start_at(fc)
- chart.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(chart.spy())
-
-If we ran the above code we would see the expected behavior:
-
-.. code-block:: python
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'INIT_SIGNAL:fc',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'EXIT_SIGNAL:fc1',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)']
-
-
-.. _towardsthefactoryexample-unwinding-a-factory-state-method:
-
-Unwinding a Factory State Method
---------------------------------
-State methods made from factories are hard to debug because you can't actually
-see their code. If you find that you have an issue with such a state method, you
-can unwind it into flat code using the ``to_code`` method. This method outputs a
-string that you can use as a hand written state method.
-
-In the following example, I'll show how we can 'unwind' a design.
-
-.. image:: _static/factory4.svg
- :target: _static/factory4.pdf
- :align: center
-
-First we repeat the work of the last section:
-
-.. code-block:: python
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- # create the states
- fc = state_method_template('fc')
- fc1 = state_method_template('fc1')
- fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- ao.register_parent(fc2, fc)
-
-The ``fc``, ``fc1`` and ``fc2`` objects contain state methods that were
-generated by the framework and their code is hidden within the ``ao`` object.
-
-Now suppose something were to go wrong with this design? An application
-developer would have to know that there are at least four different places to
-look within the miros framework to understand their state method: the
-registration functions, the context managers and in the actual template
-generation function. That would be a lot to keep in their head while they were
-also trying to wrestle with their own design problem.
-
-Instead, they could use the ``to_code`` method, copy the result and write it
-back into the design as flat state methods. In this way they could focus their
-entire attention on their own issue. Here is how they could do it:
-
-.. code-block:: python
-
- print(ao.to_code(fc))
- print(ao.to_code(fc1))
- print(ao.to_code(fc2))
-
-This would output the following:
-
-.. code-block:: python
-
- @spy_on
- def fc(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.BB):
- status = trans_to_fc(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def fc1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc2(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
- @spy_on
- def fc2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
-They could copy these methods and re-write their original code as this, making
-sure that the comment out all of the factory code:
-
-.. code-block:: python
- :emphasize-lines: 11-24,27-40,43-56, 58-61, 66-69,71-74,76-78
-
- # create the specific behavior we want in our state chart
- def trans_to_fc(chart, e):
- return chart.trans(fc)
-
- def trans_to_fc1(chart, e):
- return chart.trans(fc1)
-
- def trans_to_fc2(chart, e):
- return chart.trans(fc2)
-
- @spy_on
- def fc(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.BB):
- status = trans_to_fc(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, chart.top
- return status
-
-
- @spy_on
- def fc1(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc2(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
-
- @spy_on
- def fc2(chart, e):
- status = return_status.UNHANDLED
- if(e.signal == signals.ENTRY_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.INIT_SIGNAL):
- status = return_status.HANDLED
- elif(e.signal == signals.A):
- status = trans_to_fc1(chart, e)
- elif(e.signal == signals.EXIT_SIGNAL):
- status = return_status.HANDLED
- else:
- status, chart.temp.fun = return_status.SUPER, fc
- return status
-
- # create the states
- # fc = state_method_template('fc')
- # fc1 = state_method_template('fc1')
- # fc2 = state_method_template('fc2')
-
- # build an active object, which has an event processor
- ao = ActiveObject()
-
- # write the design information into the fc state
- # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- # ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
- # ao.register_parent(fc, ao.top)
-
- # write the design information into the fc1 state
- # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
- # ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
- # ao.register_parent(fc1, fc)
-
- # write the design information into the fc2 state
- # ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
- # ao.register_parent(fc2, fc)
-
- # start up the active object and watch what it does
- ao.start_at(fc2)
- ao.post_fifo(Event(signal=signals.A))
- time.sleep(0.01)
- pp(ao.spy())
-
-The highlighted sections identify all of the changes to the design. New
-flattened state methods were added and the old factory code was commented out.
-If we run this code, we see that it behaves properly:
-
-.. code-block:: python
-
- ['START',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc',
- 'ENTRY_SIGNAL:fc2',
- 'INIT_SIGNAL:fc2',
- '<- Queued:(0) Deferred:(0)',
- 'A:fc2',
- 'SEARCH_FOR_SUPER_SIGNAL:fc1',
- 'SEARCH_FOR_SUPER_SIGNAL:fc2',
- 'EXIT_SIGNAL:fc2',
- 'ENTRY_SIGNAL:fc1',
- 'INIT_SIGNAL:fc1',
- '<- Queued:(0) Deferred:(0)']
-
-Metaprogramming is easy on the person who first writes the code and very hard
-on those that have to maintain or extend the design. Like anything else,
-whether it should be done or not is dependent upon the engineering trade offs.
-
-:ref:`back to examples `
+ *You know you are working with clean code when each routine you read turns out to
+ be pretty much what you expected. You can call it beautiful code when the code
+ also makes it look like the language was made for the problem.*
+
+ -- Ward Cunningham
+
+.. _towardsthefactoryexample-towards-a-factory:
+
+Using and Unwinding a Factory
+=============================
+
+.. image:: _static/factory1.svg
+ :target: _static/factory1.pdf
+ :align: center
+
+.. _towardsthefactoryexample-example-summary:
+
+Example Summary
+---------------
+1. :ref:`Standard Approach to Writing State Methods`
+2. :ref:`Registering Callbacks to Specific Events`
+3. :ref:`Creating a Statechart Using Templates`
+4. :ref:`Creating a Statechart Using A Factory`
+5. :ref:`Unwinding a Factory State Method`
+
+.. _towardsthefactoryexample-why-you-would-want-a-factory:
+
+In this example I will walk you through how to hand-code a simple state method
+then show how that same method could be written for you automatically. Then I
+will show how to re-flatten a statechart, so that you can copy this code back
+into your design to make it easier to debug. (Like looking at preprocessor
+results in c).
+
+Why a Factory?
+--------------
+The event processor uses the organization of your state methods, who their
+parents are and how they relate to each other as if they defined a complicated
+data structure. These state methods contain your application code too, but
+they `are` the nodes of your graph; they define the topology of your
+statechart.
+
+When you send an event which will cause a transition across multiple states with
+complicated entry/exit/init event triggering to provide the Harel Formalism,
+you don't have to worry about how it is implemented, you just need to ensure
+that you have framed in your state methods with enough structure that the event
+processing algorithm can discover the graph and build out the expected behavior.
+
+This provides the illusion that you are using a completely different type of
+programming language, but it's still all Python. Your state methods are just
+being called over and over again with different arguments.
+
+Miro Samek describes this as "an inversion of control". By using his event
+processing algorithm, you are packing the management complexity of the
+topological search into the bottom part of your software system. By pushing
+this to the bottom, you can focus on writing concise descriptions of how your
+system should behave without concerning yourself with how to implement this
+behavior, the algorithm solves that problem. You just need to build the map.
+
+But to do this, the event processor expects all of your state methods to have a
+specific shape. Their method signatures have to look a certain way and their
+if-else structures have to be framed-in just right, otherwise the event
+processor will get lost while it's searching for the correct behavior.
+
+Wouldn't it be nice if the library wrote the methods for you too? Well it can,
+you can use a factory to create state method nodes, then link in event
+callbacks and assign parents at run time. The benefit of such an approach is
+that you can avoid the strangeness of a state method. It will become harder
+for a maintenance developer to accidentally break your statechart by making
+something that looks like an innocuous change. The factory hides the
+topological structure of your state methods behind another layer of
+indirection.
+
+However, if you use this library to write your state methods for you, you are
+placing yet another layer of abstraction between you and your design. A bug
+might be even harder to find than it was before. The nice thing about the
+state methods is that they are easy to understand, they are flat, and you can
+literally see the code and break within it for debugging. The cognitive
+difficulty experienced while trouble shooting a flat state method is much less
+than it would be for something that is auto-generated.
+
+
+.. _towardsthefactoryexample-standard-approach:
+
+Standard Approach to Writing State Methods
+------------------------------------------
+
+.. image:: _static/factory1.svg
+ :target: _static/factory1.pdf
+ :align: center
+
+To create the above diagram we would define three state methods, ``c``, ``c1``
+and ``c2`` and an active object.
+
+.. code-block:: python
+ :emphasize-lines: 42
+
+ import time
+ from miros import spy_on, pp
+ from miros import ActiveObject
+ from miros import signals, Event, return_status
+
+
+ @spy_on
+ def c(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.INIT_SIGNAL):
+ status = chart.trans(c1)
+ elif(e.signal == signals.BB):
+ status = chart.trans(c)
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def c1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.A):
+ status = chart.trans(c1)
+ else:
+ status, chart.temp.fun = return_status.SUPER, c
+ return status
+
+
+ @spy_on
+ def c2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.A):
+ status = chart.trans(c1)
+ else:
+ status, chart.temp.fun = return_status.SUPER, c
+ return status
+
+
+ ao = ActiveObject()
+ ao.start_at(c2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01) # give your active object a moment to respond
+ pp(ao.spy())
+
+An active object has its own thread, so when you want to communicate to it by
+posting an event, you have to give it the briefest opportunity to react.
+This delay is highlighted in the above code.
+
+When the above code is run, it would output this to your terminal:
+
+ .. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:c2',
+ 'SEARCH_FOR_SUPER_SIGNAL:c',
+ 'ENTRY_SIGNAL:c',
+ 'ENTRY_SIGNAL:c2',
+ 'INIT_SIGNAL:c2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:c2',
+ 'SEARCH_FOR_SUPER_SIGNAL:c1',
+ 'SEARCH_FOR_SUPER_SIGNAL:c2',
+ 'EXIT_SIGNAL:c2',
+ 'ENTRY_SIGNAL:c1',
+ 'INIT_SIGNAL:c1',
+ '<- Queued:(0) Deferred:(0)']
+
+We see from the spy log that we had two run to completion events with no
+surprises. Notice that the event processor tried to call the state functions
+with the ``ENTRY_SIGNAL``, ``INIT_SIGNAL`` and ``EXIT_SIGNAL`` as it should
+have, even though our state methods did not handle these events. The handlers
+for these events were left out of the state method examples to keep the code
+compact. This demonstrates that the event processor assumes that a missing
+handler for ``entry``, ``init`` and ``exit`` signals are handled by a state
+method.
+
+.. _towardsthefactoryexample-registering-callbacks-to-specific-events:
+
+Registering Callbacks to Specific Events
+----------------------------------------
+To build our state method code generation we need to create something that is
+common to all state methods. The state method does two different things, it
+responds to events and it returns parent information.
+
+To break this down even more, we can say that it does four things. It asks two
+questions and answers two questions. It asks "How should I respond to the
+events that I care about?" and "Who is my parent?".
+
+Then it answers these questions with information specific to that state method.
+To make something common across all state methods we can ask the questions but
+we can't answer them. The answers will have to be injected into the state
+methods after they have been created.
+
+To be more specific a general state method could look something like this:
+
+.. code-block:: python
+ :emphasize-lines: 4-6, 8-11
+
+ @spy_on
+ def general_state_method(chart, e):
+
+ # How should I respond to the events that I care about?
+ with chart.signal_callback(e, general_state_method) as fn:
+ status = fn(chart, e)
+
+ # Who is my parent?
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+We see that the chart argument provides different context managers,
+``signal_callback`` and ``parent_callback``. It is within these context
+managers that the answers are made.
+
+To inject the information into the chart
+object so that these context managers have something to answer with we can use the
+``register_signal_callback`` and the ``register_parent`` of the active object.
+
+Things should become a bit clearer with an example, reconsider our previous design:
+
+.. image:: _static/factory3.svg
+ :target: _static/factory3.pdf
+ :align: center
+
+
+.. code-block:: python
+ :emphasize-lines: 4, 16, 28
+
+ @spy_on
+ def tc(chart, e):
+
+ with chart.signal_callback(e, tc) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ @spy_on
+ def tc1(chart, e):
+
+ with chart.signal_callback(e, tc1) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ @spy_on
+ def tc2(chart, e):
+
+ with chart.signal_callback(e, tc2) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback() as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+To distinguish these state methods from the previous ones we pre-pend their names
+with `t` which stands for template.
+
+These state methods almost look identical, the highlighted lines spell out how
+they are different; the ``signal_callback`` context manager is using the state
+method's name to get its information. Other than that it hardly seems worth
+writing out the code three times.
+
+Now we have to give it the information required to perform the actions we want,
+first we define some callback methods, then we describe how we want our state
+methods to call them.
+
+.. code-block:: python
+ :emphasize-lines: 1-11, 13, 15-31
+
+ def trans_to_tc(chart, e):
+ return chart.trans(tc)
+
+ def trans_to_tc1(chart, e):
+ return chart.trans(tc1)
+
+ def trans_to_tc2(chart, e):
+ return chart.trans(tc2)
+
+ def do_nothing(chart, e):
+ return return_status.HANDLED
+
+ ao = ActiveObject()
+
+ ao.register_signal_callback(tc, signals.BB, trans_to_tc)
+ ao.register_signal_callback(tc, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc, signals.INIT_SIGNAL, trans_to_tc1)
+ ao.register_parent(tc, ao.top)
+
+ ao.register_signal_callback(tc1, signals.A, trans_to_tc2)
+ ao.register_signal_callback(tc1, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc1, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc1, signals.INIT_SIGNAL, do_nothing)
+ ao.register_parent(tc1, tc)
+
+ ao.register_signal_callback(tc2, signals.A, trans_to_tc1)
+ ao.register_signal_callback(tc2, signals.ENTRY_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc2, signals.EXIT_SIGNAL, do_nothing)
+ ao.register_signal_callback(tc2, signals.INIT_SIGNAL, do_nothing)
+ ao.register_parent(tc2, tc)
+
+In the first highlighted block we create four different callback methods. They
+have the same method signature as a state method and they work exactly as they
+would if they were defined within a state method.
+
+The second block is just an instantiation of an active object, it has the event
+processor and it also provides a means to register callback methods for events
+and to register a parent state.
+
+The next block shows how are three state methods are given their information.
+For instance, the event ``BB`` will cause state ``tc`` to transition to itself.
+
+If we run this code like we did in our previous example we would expect to it
+behave the same:
+
+.. code-block:: python
+
+ ao.start_at(tc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01) # give your active object a moment to respond
+ pp(ao.spy())
+
+If we ran this code, we would see:
+
+ .. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc',
+ 'ENTRY_SIGNAL:tc',
+ 'ENTRY_SIGNAL:tc2',
+ 'INIT_SIGNAL:tc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:tc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:tc2',
+ 'EXIT_SIGNAL:tc2',
+ 'ENTRY_SIGNAL:tc1',
+ 'INIT_SIGNAL:tc1',
+ '<- Queued:(0) Deferred:(0)']
+
+.. _towardsthefactoryexample-registering-a-parent-to-a-state-method:
+
+Creating a Statechart Using Templates
+-------------------------------------
+We pretty much wrote the same method three times in a row in our :ref:`last
+example`.
+Wouldn't it be nice if something could write the thing for us?
+
+This is exactly what the ``miros.hsm.state_method_template`` does.
+
+It writes the template code within another function, then copies it so that
+this function result is unique in memory, then it renames it and then decorates
+it with some instrumentation.
+
+.. code-block:: python
+
+ from miros import spy_on
+
+ def state_method_template(name):
+
+ def base_state_method(chart, e):
+
+ with chart.signal_callback(e, name) as fn:
+ status = fn(chart, e)
+
+ if(status == return_status.UNHANDLED):
+ with chart.parent_callback(name) as parent:
+ status, chart.temp.fun = return_status.SUPER, parent
+
+ return status
+
+ resulting_function = copy(base_state_method)
+ resulting_function.__name__ = name
+ resulting_function = spy_on(resulting_function)
+ return resulting_function
+
+With this method we can automatically write our state methods then register
+event callbacks and parent states.
+
+Let's re-create our example, this time using this ``state_method_template``
+method:
+
+.. image:: _static/factory4.svg
+ :target: _static/factory4.pdf
+ :align: center
+
+.. code-block:: python
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ # create the states
+ fc = state_method_template('fc')
+ fc1 = state_method_template('fc1')
+ fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ ao.register_parent(fc2, fc)
+
+ # start up the active object and watch what is does
+ ao.start_at(fc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(ao.spy())
+
+This is a much more compact version of our map. I removed the registration of
+signals that weren't being used by the design, but more importantly I used the
+``state_method_template`` to create the state methods that could have
+information added to them with the active object registration methods.
+
+The output from this program is:
+
+.. code-block:: python
+ :emphasize-lines: 7,14
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'EXIT_SIGNAL:fc2',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)']
+
+Which is the expected behavior.
+
+.. _towardsthefactoryexample-using-the-factory-class:
+
+Using the Factory Class
+-----------------------
+The ``active_object`` module's Factory class provides a syntax which is similar to
+the previous miros version. It has the ``create``, ``catch`` and ``nest``
+methods, but it also extends the other API with ``to_method`` and ``to_code``.
+
+The Factory class wraps the ``register_signal_callback`` and
+``register_parent`` described in the :ref:`previous
+section`
+making syntax that is a bit more concise.
+
+.. image:: _static/factory5.svg
+ :target: _static/factory5.pdf
+ :align: center
+
+Here is how you could implement this statechart with the ``Factory`` class:
+
+.. code-block:: python
+ :emphasize-lines: 15
+ :linenos:
+
+ from miros import ActiveObject
+ from miros import signals, Event, return_status
+ from miros import Factory
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ chart = Factory('factory_class_example')
+
+ fc = chart.create(state='fc'). \
+ catch(signal=signals.B, handler=trans_to_fc). \
+ catch(signal=signals.INIT_SIGNAL, handler=trans_to_fc1). \
+ to_method()
+
+ fc1 = chart.create(state='fc1'). \
+ catch(signal=signals.A, handler=trans_to_fc2). \
+ to_method()
+
+ fc2 = chart.create(state='fc2'). \
+ catch(signal=signals.A, handler=trans_to_fc1). \
+ to_method()
+
+ chart.nest(fc, parent=None). \
+ nest(fc1, parent=fc). \
+ nest(fc2, parent=fc)
+
+ chart.start_at(fc)
+ chart.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(chart.spy())
+
+If we ran the above code we would see the expected behavior:
+
+.. code-block:: python
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'INIT_SIGNAL:fc',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'EXIT_SIGNAL:fc1',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)']
+
+
+.. _towardsthefactoryexample-unwinding-a-factory-state-method:
+
+Unwinding a Factory State Method
+--------------------------------
+State methods made from factories are hard to debug because you can't actually
+see their code. If you find that you have an issue with such a state method, you
+can unwind it into flat code using the ``to_code`` method. This method outputs a
+string that you can use as a hand written state method.
+
+In the following example, I'll show how we can 'unwind' a design.
+
+.. image:: _static/factory4.svg
+ :target: _static/factory4.pdf
+ :align: center
+
+First we repeat the work of the last section:
+
+.. code-block:: python
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ # create the states
+ fc = state_method_template('fc')
+ fc1 = state_method_template('fc1')
+ fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ ao.register_parent(fc2, fc)
+
+The ``fc``, ``fc1`` and ``fc2`` objects contain state methods that were
+generated by the framework and their code is hidden within the ``ao`` object.
+
+Now suppose something were to go wrong with this design? An application
+developer would have to know that there are at least four different places to
+look within the miros framework to understand their state method: the
+registration functions, the context managers and in the actual template
+generation function. That would be a lot to keep in their head while they were
+also trying to wrestle with their own design problem.
+
+Instead, they could use the ``to_code`` method, copy the result and write it
+back into the design as flat state methods. In this way they could focus their
+entire attention on their own issue. Here is how they could do it:
+
+.. code-block:: python
+
+ print(ao.to_code(fc))
+ print(ao.to_code(fc1))
+ print(ao.to_code(fc2))
+
+This would output the following:
+
+.. code-block:: python
+
+ @spy_on
+ def fc(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.BB):
+ status = trans_to_fc(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def fc1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc2(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+ @spy_on
+ def fc2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+They could copy these methods and re-write their original code as this, making
+sure that the comment out all of the factory code:
+
+.. code-block:: python
+ :emphasize-lines: 11-24,27-40,43-56, 58-61, 66-69,71-74,76-78
+
+ # create the specific behavior we want in our state chart
+ def trans_to_fc(chart, e):
+ return chart.trans(fc)
+
+ def trans_to_fc1(chart, e):
+ return chart.trans(fc1)
+
+ def trans_to_fc2(chart, e):
+ return chart.trans(fc2)
+
+ @spy_on
+ def fc(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.BB):
+ status = trans_to_fc(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, chart.top
+ return status
+
+
+ @spy_on
+ def fc1(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc2(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+
+ @spy_on
+ def fc2(chart, e):
+ status = return_status.UNHANDLED
+ if(e.signal == signals.ENTRY_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.INIT_SIGNAL):
+ status = return_status.HANDLED
+ elif(e.signal == signals.A):
+ status = trans_to_fc1(chart, e)
+ elif(e.signal == signals.EXIT_SIGNAL):
+ status = return_status.HANDLED
+ else:
+ status, chart.temp.fun = return_status.SUPER, fc
+ return status
+
+ # create the states
+ # fc = state_method_template('fc')
+ # fc1 = state_method_template('fc1')
+ # fc2 = state_method_template('fc2')
+
+ # build an active object, which has an event processor
+ ao = ActiveObject()
+
+ # write the design information into the fc state
+ # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ # ao.register_signal_callback(fc, signals.INIT_SIGNAL, trans_to_fc1)
+ # ao.register_parent(fc, ao.top)
+
+ # write the design information into the fc1 state
+ # ao.register_signal_callback(fc, signals.BB, trans_to_fc)
+ # ao.register_signal_callback(fc1, signals.A, trans_to_fc2)
+ # ao.register_parent(fc1, fc)
+
+ # write the design information into the fc2 state
+ # ao.register_signal_callback(fc2, signals.A, trans_to_fc1)
+ # ao.register_parent(fc2, fc)
+
+ # start up the active object and watch what it does
+ ao.start_at(fc2)
+ ao.post_fifo(Event(signal=signals.A))
+ time.sleep(0.01)
+ pp(ao.spy())
+
+The highlighted sections identify all of the changes to the design. New
+flattened state methods were added and the old factory code was commented out.
+If we run this code, we see that it behaves properly:
+
+.. code-block:: python
+
+ ['START',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc',
+ 'ENTRY_SIGNAL:fc2',
+ 'INIT_SIGNAL:fc2',
+ '<- Queued:(0) Deferred:(0)',
+ 'A:fc2',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc1',
+ 'SEARCH_FOR_SUPER_SIGNAL:fc2',
+ 'EXIT_SIGNAL:fc2',
+ 'ENTRY_SIGNAL:fc1',
+ 'INIT_SIGNAL:fc1',
+ '<- Queued:(0) Deferred:(0)']
+
+Metaprogramming is easy on the person who first writes the code and very hard
+on those that have to maintain or extend the design. Like anything else,
+whether it should be done or not is dependent upon the engineering trade offs.
+
+:ref:`back to examples `
diff --git a/docs/_static/state_recipe_15.pdf b/docs/_static/state_recipe_15.pdf
index 9d18e50..ba97d85 100644
Binary files a/docs/_static/state_recipe_15.pdf and b/docs/_static/state_recipe_15.pdf differ
diff --git a/docs/_static/state_recipe_15.svg b/docs/_static/state_recipe_15.svg
index f098a2c..a5e01f0 100644
--- a/docs/_static/state_recipe_15.svg
+++ b/docs/_static/state_recipe_15.svg
@@ -1,7 +1,7 @@
-
UMLState
- 150
- 260
+ 170
+ 450810450
@@ -31,8 +31,8 @@ valign=top
UMLState
- 550
- 500
+ 570
+ 690350160
@@ -54,8 +54,8 @@ valign=top
UMLClass
- 100
- 120
+ 120
+ 310890660
@@ -63,7 +63,7 @@ valign=top
--
live_spy
live_trace
-times_in_inner # property wrapping deque derived object
+times_in_inner # thread safe attribute
--
trace_callback(self, trace)
spy_callback(self, spy)
@@ -74,8 +74,8 @@ layer=0
UMLSpecialState
- 180
- 530
+ 200
+ 7202020
@@ -86,8 +86,8 @@ layer=3
Relation
- 190
- 520
+ 210
+ 71031040
@@ -99,8 +99,8 @@ layer=3
Relation
- 270
- 700
+ 290
+ 89054060
@@ -111,8 +111,8 @@ layer=3
Text
- 350
- 720
+ 370
+ 91038030
@@ -124,8 +124,8 @@ layer=3
UMLClass
- 110
- 0
+ 130
+ 19010030
@@ -135,8 +135,8 @@ layer=3
Relation
- 150
- 80
+ 170
+ 2703060
@@ -147,8 +147,8 @@ layer=3
Relation
- 270
- 80
+ 540
+ 2703060
@@ -158,8 +158,8 @@ layer=3
UMLClass
- 230
- 60
+ 500
+ 25010030
@@ -169,8 +169,8 @@ layer=3
UMLClass
- 110
- 60
+ 130
+ 25010030
@@ -180,8 +180,8 @@ layer=3
Relation
- 150
- 20
+ 170
+ 2103060
@@ -192,8 +192,8 @@ layer=3
Text
- 530
- 30
+ 740
+ 22027070
@@ -208,8 +208,8 @@ layer=3
UMLUseCase
- 130
- 370
+ 150
+ 5602020
@@ -221,8 +221,8 @@ layer=3
UMLUseCase
- 130
- 400
+ 150
+ 5902020
@@ -234,8 +234,8 @@ layer=3
UMLClass
- 100
- 810
+ 120
+ 1000430220
@@ -248,8 +248,8 @@ layer=0
UMLState
- 160
- 870
+ 180
+ 1060310120
@@ -268,8 +268,8 @@ valign=top
UMLState
- 130
- 850
+ 150
+ 1040370160
@@ -281,8 +281,8 @@ layer=0
Relation
- 290
- 770
+ 310
+ 9603060
@@ -293,8 +293,8 @@ layer=3
UMLState
- 480
- 300
+ 500
+ 490440380
@@ -318,8 +318,8 @@ valign=top
Relation
- 470
- 570
+ 490
+ 76010040
@@ -331,8 +331,8 @@ layer=3
UMLNote
- 770
- 380
+ 790
+ 57014070
@@ -346,8 +346,8 @@ layer=3
Relation
- 690
- 420
+ 710
+ 61010060
@@ -358,8 +358,8 @@ layer=3
UMLClass
- 350
- 60
+ 620
+ 25010030
@@ -369,12 +369,35 @@ layer=3
Relation
- 390
- 80
+ 660
+ 2703060lt=<<<<<-10.0;40.0;10.0;10.0
+
+ Relation
+
+ 310
+ 270
+ 30
+ 60
+
+ lt=<<-
+layer=3
+ 10.0;10.0;10.0;40.0
+
+
+ UMLClass
+
+ 250
+ 250
+ 150
+ 30
+
+ ThreadSafeAttributes
+
+
diff --git a/docs/introduction.html b/docs/introduction.html
index 0fe89f3..3a5681e 100644
--- a/docs/introduction.html
+++ b/docs/introduction.html
@@ -251,8 +251,8 @@
about it.
Python has advanced significantly since the 90s. UML cannot capture all of the
expressive power of the language, but it doesn’t have to; if you don’t know how
-to draw your intention (list comprehensions, generators, properties, etc.), you
-can just write the code onto your diagram.
+to draw your intention (super, list comprehensions, generators, properties,
+etc.), you can just write the code onto your diagram.
This library ports the Miro Samek event processor to Python. It provides the
diff --git a/docs/reading_diagrams.html b/docs/reading_diagrams.html
index 31f25db..0d13773 100644
--- a/docs/reading_diagrams.html
+++ b/docs/reading_diagrams.html
@@ -58,7 +58,7 @@
But do you need to read these books before you use UML? No, because we are not
going to treat UML as a formal computer language with mathematical semantics. We
will use UML as something to sketch with.
+
The formal language we will use is Python.
+
This section should give you enough information so that you can make your own
+pictures.
Software modelers depend on and use engineering analogies but often fail to
-understand them. Engineers realize that the models aren’t the product; they’re
-abstractions of the product. In fact, in most cases, the models are only
-partial abstractions of the product, used to hightlight aspects that the
-engineer should know about the product. The term
-‘executable specification’ is an oxymoron – if the specification were truly executable, it would
+understand them. Engineers realize that the models aren’t the product;
+they’re abstractions of the product. In fact, in most cases, the models are
+only partial abstractions of the product, used to highlight aspects that the
+engineer should know about the product. The term ‘executable specification’
+is an oxymoron – if the specification were truly executable, it would
actually be “the thing”. Otherwise, it would merely model “the thing,” which
by definition is partial and incomplete.
—Dave Thomas
-
The formal language we will use is Python.
-
This section should give you enough information so that you can make your own
-pictures.
If you want all of the states of your statechart to react the same when they see
a specific event, use the ultimate hook pattern.
This gives you all of the benefits of inheritance while still having debuggable
diff --git a/docs/recipes.html b/docs/recipes.html
index 89fca24..cb4341b 100644
--- a/docs/recipes.html
+++ b/docs/recipes.html
@@ -152,7 +152,9 @@
In this section I’ll show you how you can use the miros library by layering more
-and more of its features into a simple program.
+and more of its features into a simple program. This program will be arbitrary,
+it serves no purpose other than to show how to do the common things you will
+want to do when you build your own systems.
If you build a statechart using miros your program is multithreaded. This means
+that if you would like to access the same variable across two threads, you need
+to lock it so that one thread doesn’t write to it while another thread is using
+it.
+
Here is an example design of where we turn the times_in_inner attribute into a
+thread-safe property using the ThreadSafeAttributes class (available in
+miros >= 4.1.3).
There is no UML drawing syntax for describing an attribute wrapped by a
+property. There is no UML diagram to show a thread lock, or how multiple
+inheritance works through linearization of parent classes using Python super().
+Our UML is just a sketch, so we make a note that the times_in_inner
+is a thread safe attribute and move on.
+
+
The ThreadSafeAttributes class tries to protect you from race conditions by
+inspecting the line of code where the times_in_inner variable is used and
+wrap it within a thread lock. The ThreadSafeAttributes is limited in
+it’s capabilities, but it will
+lock the non-atomic += operation seen below:
It’s hidden from view. The times_in_inner is a kind of @property and
+the variable that holds its information is protected by another hidden variable
+that is the lock.
+
Running this program will provide the following output:
The f1 statechart properly reports how many times it was in its inner_state.
+The f2 inner_state doesn’t write to the times_in_inner property, so it’s
+output only shows how that property was initialized.
+
Let’s look at the thread safe code in isolation:
+
frommirosimportFactory
+# ...
+frommirosimportThreadSafeAttributes
+
+classF1(Factory,ThreadSafeAttributes):
+ _attribute=['times_in_inner']# Uses a metaclass to make the
+ # times_in_inner property, with its
+ # protecting lock
+
+ def__init__(self,name,log_file_name=None,
+ live_trace=None,live_spy=None):
+ # ...
+ self.times_in_inner=0
+
+ defsome_state(self,e):
+ # ..
+ # Inside of the state thread small operations on the times_in_inner
+ # attribute can use used in a thread safe way
+ print(self.times_in_inner)# safe
+ a=self.times_in_inner# safe
+ self.times_in_inner=1# safe
+ self.times_in_inner+=1# safe
+ self.times_in_inner+=2*self.times_in_inner# NOT safe
+ self.times_in_inner=self.times_in_inner+1# NOT safe
+ self.times_in_inner=2*self.times_in_inner# NOT safe
+
+
+
The ThreadSafeAttributes class behaves like a macro, wrapping the getting
+and setting of the thread safe attribute within a thread lock. It also wraps
+simple, +=, -=, …, <<= statements within a lock. But that’s it.
+It can’t protect other types of statements from race conditions. If you need to
+use your thread safe attribute to perform more complex operations, use a
+temporary variable and copy the results into the thread safe attribute when you
+are done.
+
Better yet, share information using published events. But, the thread safe
+attributes feature is very useful when you are sharing information between a
+statechart and a thread which is not a statechart, like main.
+
+
Note
+
Accessing a thread safe attribute will be very slow. In the background
+the ThreadSafeAttributes uses a metaclass, and the descriptor protocol.
+Within the descriptor protocol it uses the inspect library to read the
+previous line of code and compares it to a regular expression. Keep this in
+mind when you use this feature.
If you have gotten this far, you have a good handle on how to use this library
+and all of its features. But you can take it to another level though. Your
+statecharts can send encrypted messages to one another and act in concert while
+running on different machines. To see how to do this, look at the
+miros-rabbitmq library.
Here is a collection of tiny programs that each demonstrate how to do things in miros.
diff --git a/docs/searchindex.js b/docs/searchindex.js
index fc3c8ec..d17913d 100644
--- a/docs/searchindex.js
+++ b/docs/searchindex.js
@@ -1 +1 @@
-Search.setIndex({docnames:["activeobject","architecture","cellular_automata","city_sprinkler","comprehensive","concurrency_essay","event","examples","glossary","hsm","i_bitcoin_miner_toaster_oven","i_create_a_multishot","i_create_a_one_shot","i_defer_and_recall","i_determining_the_current_state","i_making_sequence_diagrams_from_trace","i_mongol_example","i_mongol_with_empathy_code_listing","i_navigation_1","i_navigation_2","i_navigation_3","i_navigation_4","i_navigation_5","i_navigation_6","i_networking_instrumentation_file_table","i_scribble_on_the_spy","i_seeing_your_signals","i_spy_reactive","i_test_with_spy","i_test_with_trace","i_thread_safe_attributes","i_trace_reactive","i_uml_trend","index","installation","interactingcharts","introduction","networked_instrumentation","patterns","postingexample","quickstart","reading_diagrams","recipes","reflection","scribbleexample","setting_up_rabbit_mq","singlechartexample","testing","thread_safe_attributes","towardsthefactoryexample","zero_to_one"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:55},filenames:["activeobject.rst","architecture.rst","cellular_automata.rst","city_sprinkler.rst","comprehensive.rst","concurrency_essay.rst","event.rst","examples.rst","glossary.rst","hsm.rst","i_bitcoin_miner_toaster_oven.rst","i_create_a_multishot.rst","i_create_a_one_shot.rst","i_defer_and_recall.rst","i_determining_the_current_state.rst","i_making_sequence_diagrams_from_trace.rst","i_mongol_example.rst","i_mongol_with_empathy_code_listing.rst","i_navigation_1.rst","i_navigation_2.rst","i_navigation_3.rst","i_navigation_4.rst","i_navigation_5.rst","i_navigation_6.rst","i_networking_instrumentation_file_table.rst","i_scribble_on_the_spy.rst","i_seeing_your_signals.rst","i_spy_reactive.rst","i_test_with_spy.rst","i_test_with_trace.rst","i_thread_safe_attributes.rst","i_trace_reactive.rst","i_uml_trend.rst","index.rst","installation.rst","interactingcharts.rst","introduction.rst","networked_instrumentation.rst","patterns.rst","postingexample.rst","quickstart.rst","reading_diagrams.rst","recipes.rst","reflection.rst","scribbleexample.rst","setting_up_rabbit_mq.rst","singlechartexample.rst","testing.rst","thread_safe_attributes.rst","towardsthefactoryexample.rst","zero_to_one.rst"],objects:{"":{activeobject:[0,0,0,"-"],event:[6,0,0,"-"],hsm:[9,0,0,"-"]},"activeobject.ActiveFabricSource":{clear:[0,3,1,""],publish:[0,3,1,""],start:[0,3,1,""],stop:[0,3,1,""],subscribe:[0,3,1,""],thread_runner_fifo:[0,3,1,""],thread_runner_lifo:[0,3,1,""]},"activeobject.ActiveObject":{append_publish_to_spy:[0,3,1,""],append_subscribe_to_spy:[0,3,1,""],cancel_event:[0,3,1,""],cancel_events:[0,3,1,""],make_unique_name_based_on_start_at_function:[0,3,1,""],run_event:[0,3,1,""],start_thread_if_not_running:[0,3,1,""],stop:[0,3,1,""],trace:[0,3,1,""]},"event.Event":{dumps:[6,4,1,""],has_payload:[6,3,1,""],loads:[6,4,1,""]},"event.SignalSource":{name_for_signal:[6,3,1,""]},"hsm.HsmEventProcessor":{augment:[9,3,1,""],child_state:[9,3,1,""],dispatch:[9,3,1,""],init:[9,3,1,""],is_in:[9,3,1,""],start_at:[9,3,1,""],top:[9,3,1,""],trans:[9,3,1,""],trans_:[9,3,1,""]},activeobject:{ActiveFabric:[0,1,1,""],ActiveFabricSource:[0,2,1,""],ActiveObject:[0,2,1,""]},event:{Event:[6,2,1,""],OrderedDictWithParams:[6,2,1,""],ReturnStatusSource:[6,2,1,""],Signal:[6,1,1,""],SignalSource:[6,2,1,""]},hsm:{HsmEventProcessor:[9,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","staticmethod","Python static method"]},objtypes:{"0":"py:module","1":"py:attribute","2":"py:class","3":"py:method","4":"py:staticmethod"},terms:{"04d":40,"0bmhjf0rke8":[],"100m":[38,50],"13th":16,"142x5zhqemk5lljxgzeitbwpv2oxqpfahj":10,"1845_rc03":[],"1980s":[],"1990s":[36,41],"1st":[46,50],"2000s":36,"2005_2006":[],"257m":5,"2nd":[40,41,46,50],"2onedcellularautomata":[],"2twodcellularautomata":[],"33691e":[],"37474f":[],"3nd":46,"3rd":37,"3th":46,"4nd":46,"4th":46,"70s":5,"75c8c":[15,31,39,42,43],"8ahweo_dgs0":[],"90s":36,"95a8c":[15,42,43],"abstract":[16,38,41,49],"break":[5,15,16,30,38,39,40,41,42,43,46,48,49,50],"case":[12,16,39,40,41,42,46,50],"catch":[8,10,16,17,35,37,38,40,41,49,50],"class":[0,6,7,8,9,10,14,16,17,18,19,20,21,22,23,26,30,36,38,39,40,43,44,47,48,50],"default":[0,16,38,42,45,50],"enum":6,"final":[8,9,16,36,37,38,39,46,50],"float":[5,50],"function":[0,4,6,8,9,11,14,35,36,38,39,41,43,48,49,50],"import":[5,10,12,16,17,26,27,28,29,35,38,39,40,42,43,46,48,49,50],"int":[26,42,43,50],"long":[16,35,38,39,40,42,50],"new":[0,5,6,8,9,16,27,28,29,36,37,38,39,40,41,42,43,44,45,46,49,50],"public":[36,40,45,46],"return":[0,6,8,9,10,11,12,16,17,25,35,36,37,38,39,40,41,42,44,46,49,50],"short":[16,38,41,44,50],"static":[6,16,37,39,42],"super":[5,9,10,11,12,16,17,25,37,38,39,40,41,42,44,46,49,50],"switch":[4,30,38,48,50],"throw":[15,16,42,43,50],"true":[0,6,8,9,10,11,12,16,17,37,38,39,40,41,42,43,44,46,50],"try":[5,9,16,30,36,37,38,39,40,41,42,44,46,48,49,50],"typeof":[],"var":[],"while":[4,5,8,11,15,16,17,30,36,37,38,39,40,41,42,43,45,46,48,49,50],Adding:37,And:[16,17,41,50],Are:50,Being:50,But:[16,30,36,37,38,39,40,41,42,43,44,45,48,49,50],Eve:50,For:[0,6,8,28,37,38,40,41,42,43,46,48,49,50],GPS:40,Going:[],His:[5,16,36,50],Its:40,NOT:[0,45,46],Not:[8,50],One:[8,16,33,39,44,48],Such:[16,41,50],THE:[],That:[5,16,29,35,38,39,42,43,44,49,50],The:[0,2,4,5,6,8,9,10,11,12,15,17,26,27,29,30,31,35,36,38,39,40,42,44,45,46,47,48,49,50],Their:[5,9,16,49],Then:[5,9,15,16,35,36,38,39,40,41,42,43,44,46,49,50],There:[0,5,8,9,13,16,31,35,36,37,38,39,40,41,42,43,44,45,50],These:[5,9,16,30,36,38,41,45,48,49,50],Use:[5,37,38,50],Used:9,Useful:9,Using:[7,16,36],WLS:[],With:[16,29,39,41,42,43,49,50],Yes:[42,50],__add__:[16,17],__getattr__:[26,42,43],__init__:[6,10,16,17,37,38,40,41,42,48,50],__main__:[10,16,37,40,41,42,44,50],__name__:[10,16,37,40,41,42,44,49,50],__post_ev:0,_attribut:48,_blank:[],_decrypt:37,_dict:40,_encrypt:37,_fake_new:38,_fake_news_gener:38,_gener:[],_id:40,_imag:[],_lock:48,_recip:[],_rlock:48,_static:40,_strip_trac:37,_time_in_inn:[],_times_in_inn:[],_valu:48,a01:42,a02:42,a11:41,a1_entri:42,a1_to_b1:42,a53:50,aa00ff:[],abandon:[41,42],abil:[8,16,36,39,50],abl:[8,16,37,38,41,43,50],about:[0,5,8,9,11,12,15,16,27,28,31,37,38,39,40,43,44,45,46,48,49,50],abov:[4,9,15,16,29,37,38,39,40,41,42,43,44,45,46,48,49,50],abs:[],absenc:[],absent:[],absolut:[16,42,48],absorb:[],academ:[],acceler:8,acceleromet:[],acceller:[],accept:[30,37,42,47,48],accerer:[],access:[5,8,16,26,27,30,36,37,38,40,41,42,43,48,50],accid:42,accident:[16,41,49,50],accomod:50,accord:[8,16,41],account:[5,10,39,40,50],accumul:[41,50],accur:16,achiev:[5,16,40],acquisit:38,acronym:50,across:[6,9,16,26,30,36,38,39,41,42,43,45,48,49,50],act:[5,9,13,15,16,17,36,37,38,39,40,41,42,43,48,50],action:[0,8,9,16,36,39,41,42,44,46,49,50],activ:[1,4,5,8,11,15,16,25,27,28,29,30,31,35,36,37,38,39,40,41,43,44,48,49,50],active_object:[49,50],active_object_input_queu:0,activefab:[],activefabr:[0,42,46],activefabricsourc:0,activefactori:41,activefrab:[],activeobect:[42,50],activeobject:[0,10,16,38,39,40,41,43,44,46,49,50],activeobjectinstrumenttolog:42,activeoobject:[],actor:[41,50],actual:[5,8,9,15,16,17,28,31,35,36,38,41,42,43,44,46,48,49,50],adapt:38,add:[5,6,8,9,12,16,25,30,35,38,39,40,41,45,46,48,50],add_member_if_need:16,add_timeout:37,added:[6,16,36,37,39,40,42,49,50],adding:[8,16,38,50],addit:[4,8,16,37,42,43,48,50],address:[16,17,37,45,50],adher:[8,16,41],adjac:[9,36],adjust:[4,15,16,17,36,37,38,39,42,43,44],admistr:8,advanc:[9,16,17,36,41],advance_close_enough_for_circl:[16,17],advance_entri:[16,17],advance_exit:[16,17],advance_other_advanced_war_cri:[16,17],advance_senior_advanced_war_cri:[16,17],advance_war_cri:[16,17],advantag:16,adventur:50,advertis:50,advic:50,advis:50,advoc:[],aesthet:50,af_inet:37,affair:16,affect:[],afford:[],after:[4,5,8,16,27,28,36,38,39,40,41,42,43,44,45,46,48,49,50],afternoon:[],again:[0,9,16,35,38,39,40,42,44,46,48,49,50],against:[8,16,26,29,37,39,42,43,44,48,50],agent:16,aggreg:[24,37,38,41],aggress:38,aggression_max:38,agil:[],ago:[],agre:38,agress:38,ahead:[11,42],aim:[9,16],ain:16,air:5,aircraft:5,airforc:[],alan:[36,40,42],alarm:9,albert:41,alcohol:50,aleph2c:[40,41],alert:[],alexand:[8,38],algebra:16,algorithm:[8,9,36,38,39,42,44,49,50],align:[],aliv:[16,41],all:[0,4,5,6,8,9,11,15,16,17,24,27,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],all_readi:38,alli:[],allow:[4,8,16,37,38,39,40,45,46,50],allowfullscreen:[],allur:16,almost:[16,39,41,47,48,49,50],alon:[16,42,50],along:50,alpha:[],alreadi:[5,9,16,17,36,38,40,41,42,45,46,50],also:[4,5,6,8,9,11,15,16,30,36,37,38,39,40,41,42,43,44,45,48,49,50],altan:[16,17],altan_192:16,alter:16,alwai:[5,8,9,16,38,39,41,42,45,50],alzheim:[],ambiti:[38,43],american:5,ammunit:[16,17],ammunition_low:[16,17],amoungst:[],amount:[5,16,27,38,41,42,43,50],ampl:[],amplifi:[39,43],analog:[41,44],analysi:[],analyz:[],ancestor:[9,16,50],ancestr:16,anchor:8,angl:8,angle_in_radian:[],angri:16,ani:[0,4,5,6,8,9,12,16,26,37,38,39,40,41,42,43,44,46,47,48,50],anim:36,annihil:50,annoi:50,announc:50,anoth:[4,5,6,8,9,15,16,17,30,31,35,36,37,38,39,40,41,43,44,45,46,48,49,50],answer:[5,16,30,36,40,41,47,48,49,50],anthropologist:36,anti:[41,42,50],antiqu:[],anymor:[16,39,42,50],anyon:[16,36,39,43,48,50],anyth:[5,39,40,41,42,43,49,50],anytim:[8,16,30,37,38,42,46,50],anywai:[41,50],anywher:[16,41,50],ao1:[42,43],ao2:42,aos:[11,39,42],apart:[5,38,50],api:[0,11,12,16,25,36,37,40,41,42,46,49,50],api_hold_off_time_in_sec:40,api_kei:40,api_l:40,api_live_entry_sign:40,api_live_fresh_api_cal:40,api_live_init_sign:40,api_live_network_error:40,api_lookup_data:40,api_lookup_data_city_detail:40,api_lookup_data_entry_sign:40,api_lookup_data_init_sign:40,api_lookup_data_request_city_detail:40,api_paus:40,api_paused_entri:40,api_paused_get_weath:40,api_query_url:40,api_weather_dict:40,apologet:[],app:[45,50],appear:[16,42,50],append:[0,6,9,16,17,37,41,48],append_publish_to_spi:0,append_subscribe_to_spi:0,append_to_spi:37,append_to_trac:37,appendix:50,appid:40,appli:[8,16,36,42,46,48,50],applic:[5,16,36,41,42,49,50],approach:[0,5,8,9,16,36,38,42,44,50],appropri:[],approxim:[],apt:45,arab:5,arbitrari:16,arcan:41,archan:[],archer:[7,17],architect:[8,38],architectur:[16,33,38,39,42,50],area:[5,38,41],aren:[5,8,16,38,39,41,42,50],arg:[6,9,40,41,42,48,50],argu:16,arguement:41,arguemnt:[],argument:[8,9,11,37,39,41,42,46,49,50],aris:[16,38,50],arm:[15,16,28,29,31,38,39,42,43,50],armi:16,armin:8,armli:[],armour:16,around:[5,8,16,29,37,38,42,43,48,50],arrai:[9,38,50],arrang:50,array_equ:[],arriv:[16,50],arrow:[8,9,16,17,37,38,39,40,42,44,46,50],art:[37,42,46],articl:36,artifact:[42,50],artifici:[8,13,38,42],ascend:50,ascii:[8,15,37,42,43,50],asctim:42,asid:[],ask:[5,16,36,37,38,39,40,41,42,44,46,47,49,50],aspect:[36,38,41,42,50],assert:[0,6,9,16,28,29,38,41,42,43,50],assign:[0,9,42,48,49,50],assimil:[],assist:[15,42,43],associ:[0,39,42,44,50],assort:[],assum:[16,27,38,40,41,42,43,44,49],assumpt:[36,38],asychron:[],asycio:36,asymetr:50,asymmetr:36,asynchron:[5,8,36,41,42],asyncio:50,at15:50,atan:[],ativeobject:[],atom:[30,44,48],attach:[40,46,50],attachment_point_1:41,attachment_point_2:41,attack:[16,17,44],attempt:36,attent:[4,5,9,15,16,35,38,39,41,42,43,46,49,50],attractor:16,attribut:[1,6,7,9,10,16,30,37,38,39,40,41,46,50],attribute_1:41,attribute_2:41,attributut:[],audienc:[41,50],augment:[9,11,38,39,41,42,50],augustin:5,aureliu:[],australia:[],author:[36,38],authorized_kei:45,authorizing_author:38,authorizing_entri:38,autist:16,auto:[42,49],autocorrel:[],autodoc:[],autom:45,automat:[16,38,40,41,42,45,49,50],automata:7,autonom:16,autonoma:[],autoplai:[],avail:[5,36,41,42,50],avalanch:16,avion:[5,36],avoid:[5,11,16,30,39,40,41,42,43,44,48,49,50],awai:[15,16,17,36,38,39,40,41,42,43,46,50],await:[27,42,43],awaken:50,awar:[5,16,41,42,50],awesom:[],awkward:[8,44],axi:[41,50],b11:42,b11_entri:42,b11_inner_most:42,b11_other_inner_most:42,b1_entri:42,b1_exit:42,b1_init:42,b27300:[],b35975e18dc93725acb092f7272cc6b8:40,b_chart:35,baba:32,babi:5,back:[2,3,4,8,9,16,30,35,36,37,38,39,40,41,42,44,46,48,49,50],background:[16,35,36,38,42,46,50],backward:[9,41],bad:[5,16,35,37,38,42,50],baffl:48,bafflingli:16,bait:16,bak:47,bake:[10,38,42,50],bake_press:41,bake_tim:50,bake_time_in_sec:50,baking_buzz_test_spec:50,baking_entri:38,baking_st:[],baking_time_m:50,balanc:5,ball:42,balloon:50,ban:50,bang:16,bank:38,bankruptci:[],bar:[41,50],barg:[0,8,11,42,50],barometr:40,barrag:16,barrier:[],bartend:50,base:[0,8,9,16,30,37,38,40,42,43,44,46,50],base_state_method:49,basic:[6,16,26,36,38,42,43,46],basic_consum:37,basic_publish:37,basicconfig:42,bate:16,batteri:[15,39,42,43],battery_charg:[28,29,31,39,42,43],battl:[5,16,17],battle_entri:[16,17],battle_init:[16,17],battlefield:16,battleground:5,bb_handler:35,beagleboard:50,beat:[5,11,40,42],beauti:[41,43,49],beautifulli:9,beazlei:50,becam:[5,36,41,42],becaus:[5,6,8,13,16,28,30,35,36,37,38,39,40,41,42,43,44,46,48,49,50],becom:[5,8,15,16,29,36,39,40,41,42,43,49,50],been:[0,2,4,5,6,8,9,16,28,30,34,35,36,37,38,39,40,41,42,43,44,46,48,49,50],befor:[0,5,6,8,9,10,12,16,30,36,37,38,39,40,41,42,44,45,46,48,49,50],began:[39,50],begin:[0,5,8,9,15,16,17,35,37,38,39,41,42,43,44,46,48,50],beginn:[5,48],behalf:41,behav:[4,12,15,16,17,36,38,39,40,42,43,46,48,49,50],behavior:[8,16,25,27,28,29,35,37,38,39,40,41,44,46,49,50],behavior_nam:38,behaviour:[16,36,37,50],behind:[36,49,50],being:[5,6,8,9,11,13,16,17,24,26,29,30,37,38,39,41,42,43,46,48,49,50],beings:50,belabor:42,belief:16,believ:50,belong:[16,38,50],below:[16,26,35,40,42,43,45],benefici:41,benefit:[41,42,49,50],benifit:[],bernhard:45,besid:[8,40,41,42,50],best:[0,5,8,16,41,50],better:[5,16,36,38,40,41,42,46,50],between:[5,8,9,11,12,16,17,27,30,31,36,38,39,40,41,43,44,46,48,49,50],beyond:[9,16,41,50],bia:[],bias:16,big:[8,16,37,38,39,40,41,42,44,46,50],bigger:[4,5,39,43],billion:5,bin:50,binari:8,bind:[37,47],binocular:50,biolog:36,biologi:36,bird:50,bit:[5,10,12,16,35,37,39,42,44,46,49,50],bitcoin:10,bitcoin_address:10,bitcoin_miner_off:10,bitcoin_miner_on:10,black:[8,16,39,40,41,42,44,46,50],black_mask:[],blast:16,blazingli:50,blind:[16,28,35,42,43],blissfulli:42,blit:[],blob:[],block:[5,16,30,36,38,40,41,42,44,46,48,49,50],blocking_:[],blockingconnect:37,blog:[45,50],blue:[8,42,50],blueprint:[16,41],blur:16,bluster:16,board:50,bob:[37,45],bodi:[16,37],bog:16,boiler:[41,50],boilerpl:37,bold:38,bomb:5,bombard:16,book:[5,9,36,38,39,41,44],bool:[9,41],boot:[],bordercolor:[],borg:[],boss:50,bot:[16,45],both:[0,5,8,16,30,35,37,38,40,41,42,46,48,50],bother:[15,42,43,50],botnet:16,bottl:16,bottom:[5,40,48,49,50],bottom_bound:50,bounc:50,bouncer:50,bound:16,boundari:[8,41,42,44,50],bow:[16,17],box:[37,50],boyd:36,bracket:[31,38,42,43,44],brain:[],brake:[38,42],brand:[41,42,50],brass:[],brave:16,breach:8,bread:[39,50],breakpoint:[],brethren:16,brew:[],bridg:[],briefest:49,briefli:50,bring:[5,16,42,44],broad:16,broadcast:[15,42,43],broadcast_spi:37,broadcast_trac:37,broader:41,broken:[5,16,36,37,38,40,41,42,50],broker:45,brother:16,brown:[],browser:50,brush:[],bubbl:[38,41,42,50],buffer:[8,27,38,39,40,42,43],bug:[16,30,39,40,42,48,49,50],bui:[5,43,50],build:[4,5,8,9,13,17,35,36,37,38,39,40,41,43,44,46,49,50],build_data_structur:40,build_data_structure_entry_sign:40,build_data_structure_init_sign:40,build_data_structure_read_fil:40,build_next_mask:[],build_piston:38,built:[4,8,16,31,35,36,37,38,40,41,42,43,44,50],bulbu:41,bulk:40,bullet:50,bunch:[8,16,40,50],burden:50,buri:[],burn:[],burnabi:40,burst:[16,38],burst_ev:38,bus:50,buse:36,busi:[5,8,35,36,37,38,41,50],busy_count:38,busy_entri:38,busy_time_out:38,busy_time_out_hook:38,butterfli:[],button:[36,50],buttress:50,buzz:[44,50],buzz_tim:50,buzz_time_m:50,buzzer:50,buzzspec:50,c11:42,c1_a:37,c2_a:37,c_1:41,c_1_inner_st:41,c_1_outer_st:41,c_2:41,c_2_inner_st:41,c_2_outer_st:41,c_2_outer_state_entry_sign:41,c_2_outer_state_init_sign:41,c_2_outer_state_reset:41,c_chart:35,c_trace_consum:[24,37],c_trace_produc:[24,37],cach:40,cached_payload:40,cachefilechart:41,caf_second:[16,17],calcium:[],calcul:[30,48],calculu:16,call:[0,4,5,8,9,11,12,13,16,26,27,30,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],call_something_lat:50,callback:[8,16,17,35,38,42,50],callback_method:37,caller:[8,38],calori:[],came:[5,8,12,16,27,38,40,42,43,50],camera:16,camil:46,camp:36,campaign:50,can:[0,2,4,5,6,7,8,9,10,11,12,13,15,16,17,25,26,27,28,29,30,31,35,36,38,39,40,41,42,43,44,45,46,47,48,49,50],canada:[],cancel:[0,11,12,39,40,50],cancel_ev:[0,11,12,16,17,39,40,42,50],cancel_sourc:42,cannot:[36,38],canva:41,capabili:[],capabl:[37,41],capacitor:39,capacitor_charg:[28,39,42,43],captur:[11,12,16,36,38,41,42],card:16,care:[0,8,12,15,16,41,42,43,44,46,49,50],career:5,carefulli:[28,42,43,50],cargo:5,carpet:50,carri:[8,16,40,41,50],cascad:39,cast:50,casual:41,cat:[42,45],catagor:8,categori:[],caught:[8,16,38,41,42,50],caus:[4,5,16,31,35,38,39,40,41,42,43,46,48,49,50],causal:[],ccceler:[],celciu:[],cell:36,cells_per_gener:42,cellular:7,celsiu:[38,40],cement:[],center:46,centr:38,centric:36,centuri:16,ceo:5,certain:[16,49,50],certainli:16,ceullular:[],chain:[16,42],challeng:[36,50],chamber:38,chanc:[16,17,40,41,42,48,50],chang:[4,5,9,12,15,16,29,30,36,37,38,40,41,42,43,45,46,48,49,50],changebordercolor:[],channel:37,chao:[16,38],chaotic:16,chapter:[36,38],charact:[0,31,37,42,43,50],characterist:[9,16,38,50],charg:[15,16,17,39,42,43],charli:50,chart1:[41,42],chart2:[41,42],chart3:42,chart:[0,4,7,8,9,11,12,13,14,15,16,17,25,26,27,31,35,37,38,39,40,41,42,44,46,49,50],chart_2_start:41,chart_attribute_1:41,chart_attribute_2:41,chart_b:35,chart_nam:37,chase:16,cheap:[43,50],check:[0,16,40,50],chemic:36,chicken:[16,17],child:[8,9,38,42,46],child_stat:9,child_state_graph_e1_s5:9,children:16,china:36,chines:[],chip:[],choa:[],choic:50,chomski:45,choos:[16,40,50],choppi:[],chortl:5,chose:42,christoph:[8,38],chunk:[5,46],cira:[],circa:36,circl:[8,16,17,41,50],circle_and_fir:[16,17],circuit:[16,38,39],circul:36,circular:50,circumst:36,citat:36,citi:40,city_detail:40,city_details_payload:40,city_id:40,city_to_id_json:40,city_weath:40,citydetail:[],citydetailspayload:40,cityweath:[],claim:[38,50],clariti:6,class1usedtosolveproblem:41,class2usedtosolveproblem:41,class_with_embedded_chart:[],classwithembeddedchart:41,classwithstatechartinit:42,claus:[8,38,41,42,50],clean:[6,49,50],clear:[0,9,16,29,30,40,42,43,46,48,50],clear_spi:[37,44,46,50],clear_trac:[16,37,42,46,50],clearer:[44,49,50],click:[4,8,16,38,41,50],client:[8,16,38,40],client_dequ:0,climb:[9,38,42,46,50],clip:50,clobber:9,clock:[30,36,38,48,50],clone:41,close:[10,16,17,38,39,41,50],close_enough_for_circl:[16,17],closer:16,closest:16,closur:37,cloud:40,club:38,clue:50,clumsi:37,cluster:[],clutter:[37,38,41,42,50],cmap:[],cod:40,code:[0,2,4,5,6,8,9,10,13,15,16,17,18,19,20,21,22,23,24,27,29,30,35,36,38,39,40,41,43,45,46,48,49],codebas:[40,48],cognit:[16,36,39,44,49],cohes:16,collabor:[16,38],collect:[5,6,8,9,16,36,37,40,41,42,45,50],collegu:35,collis:44,colon:36,color:[],color_numb:[],colour:37,column:[],com:41,combin:[],come:[4,5,8,15,16,36,37,38,39,40,41,42,43,45,46,50],comfort:[16,36,37],command:[5,16,17,28,38,42,43,45],comment:[9,15,16,28,38,39,42,43,49,50],commerci:42,committe:41,commmon:8,common:[8,9,30,38,41,42,47,48,49,50],common_behavior:[40,42],common_behaviors_entri:42,common_behaviors_entry_sign:40,common_behaviors_heart_beat:40,common_behaviors_hook_1:42,common_behaviors_hook_2:42,common_behaviors_init:42,common_behaviors_other_inner_most:42,common_behaviors_reset:42,common_behaviors_to_summ:40,common_behaviors_weath:40,common_featur:50,commonplac:[],commun:[0,5,8,16,35,36,38,40,41,47,49,50],comp:38,compact:[16,36,40,41,42,43,49],compani:[36,41,45,50],companion:50,compar:[5,16,26,28,29,37,38,40,41,42,43,46,50],comparison:[5,50],comparisonitem:[],compel:[],compens:5,compet:36,compil:[36,48,50],complet:[5,8,9,16,37,38,39,41,42,46,47,49,50],complete_circuit:16,complex:[5,8,16,35,36,38,41,42,43,46,48,49,50],complianc:16,compliant:[15,42,43,50],complic:[5,16,36,38,40,41,42,43,49,50],complicit:16,compon:[4,16,36,41,50],composit:[38,41,44],compound:41,comprehend:16,comprehens:[7,36],comprehensive_no_instrument:4,compress:[16,17,38,40],compromis:16,comput:[8,16,24,36,37,38,41,42,45,50],concaten:45,conceiv:[],concentr:16,concept:[8,16,36,50],conceptu:36,concern:[16,38,42,49],concert:42,concis:[35,36,49],conclud:16,conclus:16,concret:[],concurr:[30,35,36,41,42,48,50],condit:[4,5,8,16,17,30,38,39,40,41,44,48,50],conduct:[16,40],conduct_queri:40,conduct_query_entry_sign:40,conduct_query_readi:40,cone:[],conf:45,confid:[16,50],config:45,configur:[8,9,15,42,43,44,45],confin:[36,38],confirm:[16,38,44,45,50],conflict:5,confus:[16,36,41,50],connect:[8,16,35,38,40,41,42,45,46,50],connection_attempt:16,connectionparamet:37,consciou:50,consequ:16,conserv:47,consid:[5,8,9,15,16,29,38,42,43,44,50],consider:[36,40],consist:[16,37,38,40,41,50],conspir:50,conspiraci:50,constant:16,constraint:36,construct:[6,8,9,12,14,16,30,36,37,38,39,40,42,43,45,48,50],constructor:42,consult:45,consum:[8,16,24,36,40,41,42],consumpt:[16,50],contact:40,contain:[4,5,6,8,16,27,29,31,35,36,37,38,39,40,41,42,43,44,46,49,50],contemporari:50,contemptu:16,content:[1,4,16,33,39,40,41,50],context:[5,8,29,38,42,43,44,49,50],contextu:41,contin:[],continu:[5,8,16,36,38,39,41,42,46,50],contract:38,contractor:5,contradict:[36,42],contrari:44,contrast:[8,38],contribut:[8,36,41],contriv:40,control:[4,12,16,30,38,39,40,41,42,43,44,45,46,48,49,50],conu:[],conundrum:[16,36],conveni:38,convent:[16,50],convers:[41,43],converst:[],convert:[8,16,36,40,42],convinc:[16,50],cook:50,cook_tim:50,cook_time_sec:50,cool:[5,38,40,50],cool_enough:38,cooper:[],coord:40,coordin:[40,41],copi:[5,15,28,29,38,41,42,43,45,48,49,50],core:[38,50],core_color:[],corner:[16,50],coroutin:[],correct:[5,9,16,17,35,40,41,43,45,49,50],correctli:9,correspond:44,corrupt:5,cortext:50,cos:[30,48],cosmologist:47,cost:[5,8,30,36,38,40,41,42,43,48,50],couch:5,could:[5,11,15,16,17,29,30,35,36,37,38,39,40,41,42,43,44,46,48,49,50],couldn:[16,42],count:[16,38],count_down:48,countdown:[],counter:[16,42],counti:[],countri:[5,38,40],coupl:[28,36,38,41,42,43,50],cours:[16,44],cover:16,coward:16,cpu:[16,38,50],cpython:50,crack:[],craft:8,crank:50,crash:[9,37],creat:[0,5,6,8,11,12,15,16,17,31,35,36,38,39,40,41,43,44,45,46,48,50],create_burst:38,createel:[],creation:36,creativ:[],credenti:[16,37],cri:[16,17],criteria:38,criterion:38,critic:5,crockford:5,cross:36,crucial:16,crumb:39,crush:5,cry:[16,17],crypto:37,cryptographi:37,crystal:[],cscope:[],ctag:[],ctor:42,ctrl:[15,42,43],cued:[],cult:5,cultur:[5,16,36],cunningham:49,curat:[5,42],curiou:[],current:[0,8,9,16,36,38,41,43,46,50],current_numb:38,curs:43,custom:[6,39,41,42,43,46,48,50],customiz:41,customizabl:[],cut:16,cwec:41,cyan:[],cycl:[8,11,13,16,36,38,39,42,50],cyphertext:37,daemon:[39,42,46,50],dag:50,dai:5,daili:40,damag:[16,38],damn:[],danc:16,danger:[16,42,48],dark:[16,40],dash:[40,41],data:[8,9,15,16,27,36,38,40,41,42,43,45,49,50],data_readi:38,databas:40,datastructur:[],date:[16,29,42,43],datetim:[31,38,42,43,50],daunt:5,dave:41,david:[5,8,16,36,38,40,41,50],daydream:50,dd2c00:[],dead:[16,17,36],deaden:[],deadlin:37,deadlock:[5,50],deal:[30,38,39,48],dealt:41,dean:50,debt:50,debug:[11,16,28,37,40,41,42,43,44,46,49,50],debugg:[40,41,50],deceit:17,deceit_in_detail:[16,17],deceit_in_detail_tact:16,decent:[16,29,40,42,43],decid:[16,37,39,40,41,46,50],decim:50,decis:[16,36,40,41,50],declar:[37,42],decod:[37,40],decomposit:41,decompress:40,decor:[4,14,37,39,42,43,46,49,50],decoupl:[5,50],deep:[8,38,50],deeper:[41,42,50],deepest:[],deepli:[41,44],deer:[],def:[6,9,10,11,12,16,17,25,26,35,37,38,39,40,41,42,43,44,46,48,49,50],default_lookup_file_url:40,default_nam:42,defeat:16,defeat_in_detail_tact:16,defend:5,defens:5,defer:[0,4,8,11,12,13,16,17,27,28,35,37,39,40,41,43,44,46,49,50],defi:42,defin:[6,8,9,11,12,16,29,37,38,39,40,41,42,43,45,46,49,50],definit:[41,42],deg:40,degre:[38,40],deisgn:[],del:42,delai:[8,12,40,41,42,48,49,50],delay_in_m:50,delay_one_second:[12,42],delay_tim:[16,17],delayed_one_second:[12,42],delet:[38,40],delic:5,deliv:16,deliver:[],delusion:50,delv:16,demo:41,demonstr:[5,16,36,37,38,41,49,50],depend:[5,16,34,41,48,49,50],deploi:[44,45],deploy:45,depth:9,dequ:[0,8,38,50],deque_depth:42,deriv:[16,42,50],desc:50,descend:[38,41,50],descent:[],describ:[4,5,8,9,16,28,29,31,35,36,38,39,40,41,43,44,46,49,50],descript:[15,16,27,36,38,40,41,42,49,50],descriptor:48,deseri:6,design:[4,5,8,9,10,15,18,19,20,21,22,23,29,36,38,39,40,41,42,46,47,49],desir:[12,16,38,42],desk:[30,48],desktop:[],despit:[5,36,38,50],destination_ip:37,destination_port:37,destroi:[16,37,41,44,50],destroy_this_chart:41,destruct:[],destructor:[15,42,43,44],detail:[8,17,27,35,36,38,39,40,42,46,50],detect:[15,38,42,43,44],deterim:38,determin:[8,9,16,26,28,36,38,39,41,43,46,50],determinist:[30,48],deterministicli:[],develop:[5,16,30,36,39,40,41,42,48,49,50],deviat:50,devic:[8,16,39],diagram:[4,8,9,10,15,16,31,33,35,36,37,38,39,40,43,44,46,49,50],dialogu:50,diamond:[40,41],dict:[26,40,42,43],dictionari:[6,16,26,40,42,43],did:[4,5,16,35,36,38,39,40,41,42,46,49,50],didn:[8,16,36,37,38,39,40,41,42,45,46,50],didt_advance_war_cri:[16,17],didt_entri:[16,17],didt_exit:[16,17],didt_init:[16,17],didt_other_advance_war_cri:[16,17],didt_other_ready_war_cri:[16,17],didt_other_retreat_ready_war_cri:[16,17],didt_other_retreat_war_cri:[16,17],didt_other_skirmish_war_cri:[16,17],didt_retreat_war_cri:[16,17],didt_second:[16,17],didt_senior_advance_war_cri:[16,17],didt_skirmish_war_cri:[16,17],die:16,diff:[16,50],differ:[0,4,5,8,9,10,11,15,16,24,36,37,38,39,40,41,42,43,44,45,46,48,49,50],differenti:[16,36],difficult:[8,36,38,40,46,50],difficulti:49,difficultli:38,dig:[38,43],digit:[36,42,50],dimens:[16,50],dimension:16,diminish:16,direct:[16,17,36,41,50],directli:[8,16,35,38,39,40,41,42,44,48,50],directori:[9,16,41,45],disarm:38,disast:36,discard:5,disciplin:43,disconnect:37,discov:[8,9,16,17,49,50],discoveri:[5,16,50],discrib:[],discuss:[38,50],disk:[],disord:16,disorgan:16,dispatch:[0,4,8,9,16,17,37,38,42,46],dispatch_graph_a1_s1:9,dispatch_graph_f1_s0:9,dispatch_graph_f1_s22:9,dispatch_to_all_empathi:16,dispatch_to_empathi:16,displai:[42,46,50],disprov:44,disregard:42,distanc:[16,36],distil:41,distinct:[16,38],distinguish:[6,31,42,43,49,50],distort:5,distract:16,distribut:[16,38],div:[],dive:36,diverg:[],divid:[],do_noth:49,dobb:[37,45],doc:[37,38,41,45],doc_process:41,dock:50,docstr:[9,50],documen:[],document:[5,8,9,15,16,35,37,38,40,41,42,43,45,50],dodg:16,doe:[0,8,9,16,28,29,38,39,40,41,42,43,44,45,46,48,49,50],doesn:[5,6,8,9,11,16,36,37,38,39,40,41,42,43,44,46,50],dogfight:5,dogmat:5,doh:16,doing:[8,16,28,31,36,38,39,41,42,43,44,46,50],dollar:5,domain:50,domin:5,don:[8,9,11,12,15,16,27,30,36,37,39,40,41,42,43,44,45,46,47,48,49,50],done:[5,16,30,38,39,41,42,45,46,48,49,50],done_buzz_period_sec:50,done_wat:40,doom:16,door:[10,38,41,50],door_clos:[10,38,41,50],door_closed_bak:38,door_closed_init:38,door_closed_off:38,door_closed_open:38,door_closed_toast:38,door_open:[10,38,41,50],door_open_clos:38,door_open_entri:38,door_open_exit:38,dot:[8,16,38,39,40,42,44,46,50],dotenv:16,doubl:[41,42,50],doubt:16,dougla:5,dove:5,down:[12,16,30,36,37,38,39,40,41,42,43,46,48,49,50],download:[40,48],downsid:[],downward:50,draconian:16,draft:[],dragon:[],draw:[8,9,16,35,36,38,44,46,50],drawit:42,drawn:[9,37,41,42,50],dreari:43,drew:36,drift:[42,50],drill:[8,38,41],drink:[16,17,50],drive:[16,38,41,50],driven:[9,36,38,41,50],driver:[41,50],drone:[],drop:[5,16,28,41,42,43,50],drown:[16,41],drum:16,drunk:50,dry:[8,15,16,42,43,45],dtdakkeosog:[],dtype:[],due:[6,16,36,40,50],dumber:16,dump:6,durat:[39,42,50],dure:[6,8,9,16,41,50],duti:[38,41,42,50],dynam:[6,16,28,38,39,41,42,43,46,50],e_funct:44,each:[0,5,6,8,9,15,16,17,27,29,31,36,37,38,39,40,41,42,43,44,46,49,50],eae:41,ear:50,earli:[36,42,50],earshot:16,earth:50,easi:[8,16,29,30,35,36,38,39,41,42,43,44,46,48,49,50],easier:[5,15,16,26,38,39,40,42,43,49,50],easiest:[42,47],easili:[16,36,38],easy_bak:38,eat:[41,48],eco1:[],eco2:[],eco:[],econom:36,ecosystem:50,edg:[41,42,50],edit:[5,8,38,40,41,42,44],editor:[5,15,42,43,50],educ:46,edward:16,effect:[8,15,16,38,41,42,43,50],effort:[15,16,30,38,41,42,43,45,48,50],effortless:[],effortlessli:42,eight:[],einstein:41,either:[5,8,16,17,38,41,42,44,46,50],elabor:50,elaps:[40,50],electr:[8,38,40],element:[8,9,10,38,39,42,50],elev:42,elif:[8,9,10,11,12,16,17,25,38,39,41,42,44,46,49,50],ellison:50,els:[8,10,11,12,16,17,25,36,37,38,39,40,42,43,44,46,49,50],elsewher:[37,40,42,50],email:[36,42,50],emb:41,embed:[5,9,38,39,40,41,43,50],embed_load:[],emerg:[16,42],emit:37,emot:41,emotion:41,empath:16,empathet:16,empathi:[16,17],empathy_for_first_broth:16,empathy_nam:[16,17],emphas:[36,39,41],emphasi:[],empir:36,employe:[],empt:8,empti:[16,46],emptiv:[],enabl:[4,16,41,42],enable_snoop_spi:16,enable_snoop_trac:16,enact:[],enammour:[],enamor:[],enclos:[37,41,50],encod:37,encompass:16,encount:[5,16,50],encourag:50,encrypt:[16,37,45],end:[0,8,16,27,31,36,38,39,40,41,42,43,46,50],enemi:[5,16,17],energi:38,energy_gener:38,energy_generation_init:38,engag:[16,50],engin:[5,9,36,38,41,42,43,49],english:[16,38,41,50],enjoi:50,enlist:38,enough:[9,16,17,30,36,37,38,39,41,42,44,46,48,49,50],enrag:16,ensur:[0,16,35,37,39,49,50],enter:[9,12,16,17,35,38,39,41,42,44,45,46,50],enthusiast:50,entir:[16,36,40,42,49,50],entireti:43,entiti:[],entrepreneur:50,entri:[4,8,9,11,16,35,38,39,41,44,46,49,50],entropi:[],entry_sign:[6,8,10,11,12,16,17,25,26,27,28,35,37,38,39,40,41,42,43,44,46,49,50],enumer:[6,8,50],env:[16,45],env_path:16,enviro:[],environ:[16,36,45,50],envis:[],equal:40,equat:[16,30,48],equip:[16,50],equival:[16,39,50],era:46,ere:[],ergod:16,ergot:16,erlang:45,erron:16,error:[38,40,42],escap:[16,38],especi:[16,38,50],essenc:38,essenti:[36,48],estim:40,etc:[8,36,41,42,45,50],etho:50,evalu:[35,38,44],evapor:40,evaporatli:[],even:[12,16,36,38,39,41,42,45,46,49,50],event:[0,1,4,5,8,9,10,11,12,13,15,16,17,26,27,28,31,35,36,39,40,43,46,48],event_1:42,event_2:42,event_a:0,event_b:0,event_or_sign:0,event_reset_chart:46,event_wait_complet:46,eventu:[41,42,50],ever:[5,16,37,38,41,42],everi:[4,5,8,16,17,30,37,38,40,41,42,48,50],evermor:[],everyon:[16,36,38,41,43,50],everyth:[0,16,29,35,41,42,43,50],everywher:45,evid:[16,42,44,50],evolv:[36,50],evt:48,evt_a:41,exact:[28,42,43,50],exactli:[5,9,16,35,40,44,48,49,50],exam:[],examin:[39,40,44,50],exampl:[0,2,3,4,6,8,9,18,27,28,29,30,31,33,36,38,40,41,42,43,44,45,48],example1:[],example2:[],examplestatechart:4,exce:[],exceed:40,excel:45,except:[5,8,16,37,39,40,42,45,50],exception:16,exchang:[5,36,37],exchange_declar:37,exchange_typ:37,excit:50,exclud:38,exclus:37,execult:[],execut:[0,5,9,16,36,41,44,48],exercis:16,exert:16,exhaust:[39,46,50],exist:[6,8,16,36,39,40,41,42,50],exit:[0,4,8,11,16,35,37,38,39,41,44,45,46,49,50],exit_sign:[8,10,11,12,16,17,25,26,27,35,37,38,39,40,41,42,43,44,46,49,50],expand:[],expans:[],expect:[16,30,35,36,37,38,39,40,42,44,46,48,49,50],expected_empathy_target_trac:16,expected_empathy_trac:16,expens:[5,8,36,38,43,50],experi:[16,38,43,44],experienc:[16,38,42,49],experiment:16,expertli:16,explain:[0,15,16,35,36,38,40,41,42,44,50],explan:[37,47,50],explicit:[8,38,42],explicitli:[8,16,38,42,48,50],explor:50,explorequeri:[],exponenti:43,expos:[16,30,48],express:[5,6,16,36,39,40,41,42,50],extend:[8,9,16,36,37,38,49],extens:[6,8,11,42,45],extern:[0,8,16,36,38,39,41,50],extract:[38,40,42],extraordinarili:50,extrem:[5,16,30,36,41,42,48,50],extrud:[],eye:50,eyebal:[],eyes:[16,41,44,46,50],fabric:[1,8,35,42,46],fabric_task_ev:0,face:[16,42,43,47,50],facil:[38,46],facin:[],fact:[5,16,38,39,41,43,47,50],factor:8,factori:[5,7,8,14,16,17,35,37,38,40,41,43,50],factory_class_exampl:49,factory_class_recipe_exampl:42,factory_in_class:[],factoryinstrumentationtolog:42,fad:41,fade:50,fail:[9,28,38,41,42,43,50],failur:36,fairli:16,fake:[15,16,38,42,43,50],fake_black:[],fake_new:38,fake_transduc:38,fake_whit:[],fakenewsspec:38,fall:[42,50],fall_through:41,fallaci:41,fallen:41,fals:[16,38,40,41,42,44,50],falsifi:47,fame:[],famili:[16,36,48],familiar:[38,39,42,44],famous:5,fanci:[],fanout:37,far:[16,42,44,45,50],farc:50,fashion:36,fast:[16,36,38,50],faster:[16,42,50],fastest_tim:38,father:16,fathom:16,favor:[38,41],favour:16,fb11:35,fb1:35,fc1:[35,42,49],fc2:[35,49],featur:[8,9,15,16,36,37,38,40,41,42,43,48,50],fed:[16,38,50],feder:42,feed:[16,37,40,41,42],feedback:[5,16,50],feel:[5,16,36,37,38,39,41,42,44,50],feign:[16,17],feigned_retreat:[16,17],fellow:50,fermet:37,fernet:37,few:[5,16,36,38,42,50],feynman:47,ff6d00:[],ff6doo:[],ffa501:[],ffff00:[],ffffff:[],ffmpeg:[],fft:41,fiction:[],fidel:[16,50],field:[16,17,38,47],fifo:[0,8,12,16,35,39,41,50],fifo_queu:0,fifo_subscript:0,fig:[],fight:[16,41,42],fighter:[5,36],figur:[16,35,38,39,42,45,46,50],file:[8,16,24,37,40,42,45,50],filenam:42,fill:[11,16,37,38,39,42,45],film:[],filter:[5,38,42],final_icon:41,final_icon_example_1:41,finaliconexampl:41,find:[2,5,8,9,16,30,36,38,39,41,42,48,49,50],findal:50,fine:43,finish:[8,16,38,39,40,41,42,48,50],finit:[8,41],fire:[11,12,16,17,38,39,40,42,46,50],firm:[36,44],firmwar:[5,36],first:[0,6,8,9,13,15,29,30,31,36,37,38,39,40,41,42,43,46,47,48,49,50],first_brothers_nam:16,first_name_of_oth:16,firstscripttag:[],fit:[16,40,41,42,50],five:[16,40],fix:[16,28,42,43,50],fixat:16,flag:[30,48],flank:16,flash:39,flashlight:[],flat:[8,16,38,49,50],flatten:[42,49],flavor:[],flexibl:[16,38],fli:50,flip:50,float32:[],floor:39,flow:[40,42],flower:[],floweri:[],fly:[],fn_parent_state_handl:9,fn_state_handl:9,focu:[16,40,49,50],focus:[16,36,39],fodder:5,fog:16,folder:[16,41],folk:40,follow:[5,6,8,9,15,16,29,30,31,35,37,38,39,40,41,42,43,45,46,48,49,50],font:[],foo:4,food:50,fool:[38,47],foot:41,footman:[16,17],footmen:16,footprint:50,forc:[5,16,38,40,42,46],forecast:[],foreign:[24,37],foreign_hsm:37,foreign_spy_item:37,foreign_trace_item:37,foreseen:16,forev:[0,27,42,43],forget:[39,44],forgot:35,fork:41,form:[8,16,37,38,41,42],formal:[5,8,16,36,38,39,41,42,43,49,50],format:[8,10,16,17,26,37,38,40,41,42,43,50],former:5,forth:[16,50],forward:[30,36,38,41,42,48],found:[2,4,7,9,16,38,42,45,46,50],foundat:50,founder:[],four:[44,48,49],fowler:41,fr_entri:[16,17],fr_exit:[16,17],fr_other_retreat_war_cri:[16,17],fr_out_of_arrow:[16,17],fr_retreat_war_cri:[16,17],fr_second:[16,17],fragil:[16,41],fragment:36,frai:16,frame:[16,37,49],framebord:[],framework:[5,8,36,38,39,42,43,49,50],frankenstein:36,free:[5,36,38,42],freez:50,frequenc:39,fresh:38,fresh_api_cal:40,fridai:[],friedrich:39,friend:[],friendli:38,frighten:39,from:[0,4,5,6,8,9,10,12,15,16,17,24,26,27,29,30,31,35,36,37,38,39,40,41,44,46,48,49,50],from_list:[],front:[0,8,16,36,42,50],frustrat:[16,50],fsm:[8,41],fstring:42,fuck:5,fuction:[],fuel:[5,38],full:[0,4,16,17,27,28,37,38,39,42,43,46,50],fullfil:[],fun:[9,10,11,12,16,17,25,38,39,41,42,44,46,49,50],funcanim:[],functool:[37,42],fund:41,further:[8,38,41,50],furthermor:[16,38],fusion:38,fusion_act:38,fusion_active_cool_enough:38,fusion_active_entri:38,fusion_and_heat_transf:38,fusion_and_heat_transfer_fir:38,fusion_reactor:38,fusionreactor:38,futil:50,futur:[8,16,28,29,37,40,41,42,43,50],fuzzier:16,gain:[8,36,37,40,41,48],gallop:[16,17],game:[],ganbaatar:[16,17],gandbold:[16,17],gang:[15,42,43],ganssl:5,gantulga:[16,17],garbag:[6,9,42,50],garden:[],gate:40,gather:[],gave:[36,50],gaze:50,gear:38,gearbox:38,gem:[],gener:[5,8,12,15,16,29,31,36,37,38,39,41,42,43,45,49,50],general_state_method:49,genghi:16,geniu:43,geo:[],geometri:8,geopolit:46,gestur:50,get:[5,6,8,9,16,26,29,30,36,38,39,40,41,42,43,44,45,46,48,49,50],get_100ms_from_timestamp:50,get_a_nam:16,get_composite_read:38,get_id_file_from_network:40,get_id_file_from_network_entry_sign:40,get_id_file_from_network_readi:40,get_id_file_from_network_retry_after_network_error:40,get_ip:37,get_my_m:50,get_nam:16,get_readi:50,get_ready_sec:50,get_temperature_read:38,get_weath:40,getelementbyid:[],getelementsbytagnam:[],getenv:16,getlock1:48,getlock2:48,getsocknam:37,getter:[],gibberish:45,gift:[5,36],gil:50,gist:41,git:[16,41],github:[40,41],give:[15,16,17,36,39,40,41,42,43,44,46,48,49,50],given:[0,8,9,12,13,16,26,30,31,35,36,38,39,40,42,43,48,49,50],gl1:48,gl2:48,glanc:[41,50],gland:[],glee:5,global:[5,6,16,41,43,50],glossari:33,glow:[],glyph:[8,16,38,41,50],goal:[16,36,37,40,50],god:50,goddess:50,goe:[16,36,38,41,50],going:[9,16,37,38,39,40,41,42,47,48,50],gone:[12,37,42,50],good:[16,35,36,38,41,42,43,44,47,50],googl:36,got:[15,16,38,39,40,41,42,43,44,45,46,50],gotten:[16,29,42,43,50],govern:[5,41],gpio:40,grab:[30,48],grade:[],gradual:48,graffiti:42,grai:[],granit:16,grant:50,grap:[],graph:[8,9,41,42,49,50],graph_e1_s1:9,graph_e1_s2:9,graph_e1_s3:9,graph_e1_s4:9,graph_e1_s5:9,graphic:[41,42,50],great:[5,15,16,35,36,38,42,43,45,50],greater:[5,16,39,42,46,50],greedi:0,green:[40,41,42],greeter:50,grep:42,grid:[],grind:43,grok:44,groov:41,ground:[16,36],group:[16,36,40,42,50],grown:[],gstatic:[],guarante:[5,6,16],guard:[8,41],guard_exampl:41,guarente:[],guess:16,guest:[45,50],guest_password:45,guestpath:[],gui:[16,45,47,50],guid:[40,41,45],guidanc:[],guidenc:[],gun:[16,50],gusto:50,gyroscop:[],gzip:40,hack:[7,35,42,50],hacker:44,had:[5,16,27,35,36,37,39,40,41,42,43,44,46,49,50],hadan:[16,17],hadn:5,hal:50,half:5,halfwai:40,hall:50,halt:[16,17,36],hammer:40,hand:[5,8,16,40,41,42,44,49,50],handi:37,handl:[8,10,11,12,16,17,25,35,38,39,40,41,44,46,49,50],handler:[9,11,16,17,35,37,38,39,40,41,46,49,50],handwav:16,hang:[44,50],happen:[5,6,8,9,16,27,28,30,35,36,37,38,39,40,41,42,43,44,46,50],happi:50,hard:[16,30,37,41,42,44,48,49,50],harden:50,harder:[16,36,41,49,50],hardli:49,hardwar:[5,41],harel:[5,8,16,36,38,39,40,41,42,43,49,50],harm:[5,16],has:[0,5,6,8,9,12,16,17,27,28,29,31,34,35,36,37,38,39,40,41,42,43,44,46,49,50],has_payload:[6,42],hasn:[0,4,6,8,12,16,42,50],hast:5,hate:[8,38],hault:[],have:[0,2,4,5,6,8,9,12,13,14,15,16,26,27,28,29,30,31,35,36,38,39,40,41,44,45,46,48,49,50],haven:[5,16,31,37,38,39,40,41,42,43,44,45,46,48,50],hawk:5,hazard:41,head:[16,38,41,43,49,50],hear:[16,50],heard:[16,17,46],heart:[11,16,38,40,42],heart_beat:40,heartbeat:[],heat:[10,16,38,41,50],heater:[38,50],heater_off:[38,50],heater_on:[38,50],heating_element_off:10,heating_element_on:10,heating_entri:38,heating_exit:38,heating_st:50,heaven:50,heavi:[5,16,38],heavili:[16,50],heed:5,heehaw:50,hei:[],height:[],heirach:[],heirachi:[],held:[42,50],hello:[42,45,46,50],helmet:16,help:[5,16,36,38,41,43,46,50],helper:[9,50],helpless:16,her:50,here:[2,4,5,6,8,11,12,16,27,28,30,31,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],herself:50,hesit:42,heurist:16,hidden:[16,30,36,38,41,42,48,49,50],hide:[37,38,41,42,49],hierach:50,hierarch:[8,16,36,37,39,41,42],hierarchi:[8,9,16,37,39,40,42,44,50],high:[0,5,8,16,29,31,36,38,39,40,42,46,50],higher:[5,16,42,50],highest:[0,16,42,50],highli:[],highlight:[4,16,35,37,38,39,40,41,42,48,49,50],hightlight:41,him:[5,16,17,38,50],himself:16,hint:[16,39],hire:5,his:[5,8,9,16,17,36,38,39,44,49,50],histor:[],histori:[10,16],hit:[12,16,38,42,45],hmm:44,hmtl:[],hod:5,hold:[10,13,16,39,41,42,45,50],holder:[],hole:[],holi:5,hollow:50,hologram:16,holograph:16,home:16,honour:8,hood:50,hook:[4,8,16,27,28,39,41,43],hook_1:42,hook_2:42,hook_example_1:41,hook_example_2:41,hope:[5,16,39,50],hord:16,horizont:[41,50],hornet:16,hors:[7,17],horsearch:[16,17],horseback:16,horsemen:16,horserarch:16,host:45,hostnam:45,hot:35,hour:[41,43],hous:[],how:[1,4,5,8,9,11,15,16,17,25,27,31,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50],howev:[6,9,37,38,39,40,47,49,50],href:[7,18,19,20,21,22,23,36,38,40,41,42,43,47,50],hsm:[0,1,4,8,16,17,36,38,41,49,50],hsm_queues_graph_g1_s01:0,hsm_queues_graph_g1_s1:0,hsm_queues_graph_g1_s2111:0,hsm_queues_graph_g1_s22:0,hsm_queues_graph_g1_s321:0,hsmevent:0,hsmeventprocessor:[9,38],hsmtester:4,hsmtoplogyexcept:38,hsmtopologyexcept:[8,9,38,42],hsmwithqueu:[16,17,37,38],html:[7,18,19,20,21,22,23,36,38,40,41,42,43,47,50],http:[5,40],huge:[],hulagu:[16,17],human:[5,41,50],humid:40,humnan:[],hung:16,hunt:16,hurri:39,hypothes:[],hypothesi:[],i_list:50,i_thread_safe_attribut:[],iaf:5,icon:[8,38,40,42,50],id_rsa:45,idea:[5,8,11,16,27,36,38,39,40,41,42,43,46,48,50],ideal:16,ident:[41,48,49],identifi:[16,17,31,37,40,41,42,43,49,50],ideosynchroc:[],idiom:[],idiot:5,idl:[38,40,41],idle_data_readi:38,idle_entri:38,idle_entry_sign:40,idle_get_weath:40,idle_new_request:38,idle_request_city_detail:40,ids:[39,40],ieee:36,ifram:[],iframe_api:[],ignor:[0,6,8,12,16,17,38,39,41,42,44,46,50],ihbarhasvad:[16,17],iir:38,ill:[],illeg:[8,38,44,45],illus:[5,49],illustr:50,imag:[8,15,16,36,41,42,43],imagin:[8,16,30,36,38,41,42,44,48,50],imbu:40,immedi:[5,13,16,17,27,36,38,40,41,42,43,50],immens:[],immut:[6,40,41,42,50],impati:16,impedi:42,implement:[16,36,38,39,40,41,42,44,49,50],implemt:[],implicit:[],implicitli:48,impliment:[],implment:8,importantli:[5,44,49],importerror:50,impos:16,imposs:38,imprecis:16,impress:5,improv:[16,36,40,50],impuls:38,inabl:16,inadvert:41,inbox:16,incent:5,incid:[],incircl:8,includ:[4,16,41,42,45,50],incompet:16,incomplet:41,incomprehens:16,inconsist:48,inconveni:[4,38],incorpor:[],incorrect:42,incorrectli:[8,16],increas:[8,16,38,41,43,50],incred:[],increment:[16,38],increment_x:41,indec:[],independ:[16,38,40,42],indepent:41,index:[9,33],index_and_time_delai:[],indic:[8,9,31,38,41,42,43,50],indirect:49,individu:[16,17,37,38,39],industri:[5,36,39],ineffici:[],inevit:[38,43],inexpen:[],inexpens:[15,40,42,43],inf:[],infect:[],infer:44,infinit:[5,8,11,16,27,38,42,43],inflex:16,inform:[0,5,8,10,16,24,27,29,35,36,38,39,41,43,46,49,50],infra:[],infract:44,infrastructur:[36,42,45],infrastur:[],infrequ:[30,48],inherit:[0,8,9,16,37,38,39,42,46,48,50],init:[4,6,8,9,12,35,38,39,41,42,46,49,50],init_func:[],init_sign:[8,10,11,12,16,17,25,26,27,28,35,37,38,39,40,41,42,43,44,46,49,50],initi:[8,9,16,38,39,41,44,46,50],initial_condition_index:[],initial_st:9,initial_valu:38,inject:[8,16,37,38,42,49],inner:[8,11,12,16,27,36,38,39,41,42,43,46,50],inner_most:42,inner_st:[38,41,42],inner_state_1:41,inner_state_1_b:41,inner_state_1_entry_sign:41,inner_state_1_exit_sign:41,inner_state_2:41,inner_state_2_a:41,inner_state_2_entry_sign:41,inner_state_2_exit_sign:41,inner_state_entry_sign:42,inner_state_exit_sign:42,innner:39,innner_st:[],innoc:[30,48],innocu:[16,48,49],innov:[5,16,36],input:[8,16,37,38,39,40,41,42,50],insert:16,insertbefor:[],insid:[8,16,36,37,40,41,48,50],insight:5,inspect:[35,38,50],inspir:[36,38],instal:[16,33,36,37,50],instanc:[8,16,28,37,41,42,43,46,49,50],instanti:[36,38,40,41,42,49,50],instati:[],instead:[0,6,11,16,36,37,38,39,40,41,42,43,46,48,49,50],instruct:[16,44,45,50],instructor:5,instrument:[0,7,8,10,16,27,31,35,36,37,38,39,40,41,43,46,47,49,50],instrumentation_line_of_match:50,instrumentedfactori:[40,41],insur:50,intact:16,intang:16,integ:16,integr:[16,36,41,50],intellig:16,intend:[5,8,16,37,38,42,50],intens:[],intent:[16,36,38,41,42,50],intention:42,inter:48,interact:[4,5,7,9,15,16,39,40,41,42,43,46,48,50],intercept:38,interconnect:50,interest:[5,16,35,36,37,42,50],interfac:[6,16,36,37,40,41,42,50],interleav:[15,42,43,50],interlock:41,intermedi:[41,50],intermediari:[],intern:[0,6,7,8,16,18,19,20,21,22,23,27,30,36,38,40,41,42,43,46,47,48,50],internal_signals_1:41,internet:[37,42,45],interplai:[42,46],interpret:[40,50],interrel:50,interrupt:[5,38,41,46],interv:42,intervent:43,intial_condition_index:[],intimid:50,intric:16,intrins:[],intro_1:[],introduc:[16,27,30,37,38,42,43,48,50],introduct:[33,40,45],introspect:[16,17],intuit:[16,42],invent:[5,8,16,36,38,40,41,50],invers:[5,39,49,50],invert:9,invest:[41,50],investig:39,invis:[],involv:[16,35,36,38,50],inward:50,iot:36,ips:[16,17],is_al:41,is_fil:16,is_in:9,is_set:48,is_this_piston_readi:38,is_wint:40,ish:16,isn:[5,6,13,16,17,36,41,42,46,50],iso:40,isol:[43,50],isra:[5,36],issu:[8,16,17,28,29,30,37,38,40,42,43,46,48,49,50],item:[0,6,8,9,16,17,26,31,37,38,39,40,42,43,44,46,50],iter1:[18,19,50],iter2:[19,20,50],iter3:[20,21,50],iter4:[21,22,50],iter5:[22,23,50],iter6:[23,50],iter:[16,38,41,48],its:[0,4,5,8,9,15,27,30,31,35,36,38,39,40,41,42,43,45,46,48,49,50],itself:[8,16,37,38,39,40,41,42,43,44,46,48,49,50],jack:5,jacket:50,java:[41,50],javascript:[5,41],jersei:5,jet:[5,36],jinja2:[8,45],jinja:8,jitter:50,jitteri:[30,48],job:[29,39,42,43,45,50],john:36,join:[16,41,48,50],joke:16,journal:39,journei:50,json:[5,6,40,50],json_ev:6,juggl:50,jump:[9,16,36,39,50],june:36,junior:16,jupyt:50,just:[5,6,9,11,16,26,28,29,35,36,37,38,39,40,41,42,43,44,45,46,49,50],kai:[36,40,42],keel:36,keep:[0,9,16,36,37,38,39,40,41,42,44,45,49,50],kei:[5,16,26,35,37,40,42,43,45],kept:[38,50],keygen:45,keyword:[],khan:16,kill:[0,5,16,39,42,46,50],kill_tim:48,killer:48,kind:[8,13,16,30,38,39,40,41,42,46,48,50],kkk:[],knew:[37,38,46,50],knight:[16,17],know:[5,8,9,11,12,15,16,35,36,37,38,39,40,41,42,43,44,45,46,49,50],knowabl:50,knowledg:[16,40,50],known:[],korean:16,kwarg:[6,9,42],label:[9,15,39,41,42,43,46],laberg:38,lac:9,lack:[16,47],lag:16,lai:[39,50],laid:[],lame:50,lamp:38,lamp_off:38,lamp_on:38,lan:16,lanchart:41,land:[41,50],languag:[5,8,16,36,38,41,45,49],lanreccechart:41,larg:[8,9,16,36,38,41,42,46],larger:[5,16],larri:50,last:[0,8,16,35,38,40,42,46,48,49,50],last_brothers_nam:16,lastli:[],lat:40,late:[5,36,50],latenc:50,later:[9,16,37,38,39,42,50],latest:[5,16,36],latex:43,law:[5,50],layer:[16,42,49,50],lazi:[42,50],lca:[9,50],lead:[16,38,50],leader:16,leadership:[5,16],lean:[16,50],leap:[],learn:[5,7,8,16,35,38,41,42,46,50],least:[9,16,38,40,42,45,49,50],leav:[4,8,9,12,16,36,38,39,40,41,42,46,50],led:36,left:[8,16,17,37,40,41,49,50],left_wal:[],leftmost:0,legal:[],legend:50,legibl:[16,50],leisur:16,len:[16,26,37,42,43],length:9,less:[16,17,36,38,41,42,46,49,50],let:[5,10,16,17,35,36,37,38,39,40,41,42,44,46,48,49,50],letter:36,level:[5,8,16,29,31,38,39,40,42,46,50],levelnam:42,lib:[],liber:36,librari:[1,5,8,16,30,34,35,36,38,39,40,41,42,45,46,48,49,50],licenc:[],lie:16,lies:[],life:[38,42,50],lifelin:41,lifetim:[5,47],lifo:[0,8,12,41],lifo_queu:0,lifo_subscript:0,lift:[],lighlight:[],light:[10,16,36,40,41,44,50],light_off:50,light_on:50,lightweight:41,like:[5,8,9,11,12,13,15,16,26,27,29,30,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],likewis:[16,40,46,50],limbo:44,limit:[9,16,37,40,41,50],limp:[],line:[8,16,28,29,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],linear:16,linearsegmentedcolormap:[],lineno:[],ling:[],linger:16,link:[16,35,36,38,39,40,41,42,43,45,46,49,50],lint:5,linux:[37,50],lion:[],lip:[],liquid:38,list:[0,6,9,16,17,36,38,39,40,42,44,50],list_spi:50,listen:[16,37,42],listless:50,liter:49,lithium:38,litter:[],littl:[5,15,16,35,38,39,40,41,42,43,44,48,50],live:[5,8,16,37,38,40,41,50],live_spi:[16,37,40,41,43,50],live_trac:[10,16,37,40,41,42,43,50],load:[6,16,17,40,44,50],load_dotenv:16,lobotom:16,local:[8,16,17,37,38,40,45],local_consum:37,localconsum:37,localhost:45,locat:[0,8,9,16,37,38,40,41,42,50],lock:[0,5,16,30,40,41,43,48,50],lockhe:5,lockingdequ:0,log:[8,11,16,25,27,31,36,38,39,40,41,42,43,44,45,46,49,50],log_file_nam:42,logger:[],logic:[16,42,44,50],login:45,lon:40,longer:[16,38,41,42,44,50],look:[5,8,12,16,28,29,31,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],lookup_file_nam:40,lookup_file_path:40,lookup_file_url:40,lookuperror:[],loop:[0,15,16,36,39,41,42,43,46,50],loos:[8,16,38],loosen:16,lorenz:16,lose:[16,36,43,50],loss:16,lost:[16,36,41,49],lot:[5,8,15,16,35,36,38,39,40,41,42,43,45,46,48,49,50],lotteri:[],loud:16,love:[38,41,50],low:[16,17,39,42],lower:[0,5,41,42,50],lowest:[42,50],luck:[5,50],lucki:36,lure:[16,17],mac:[],machin:[6,7,8,10,16,24,36,37,38,39,41,44,45,48,50],machine_cl:[],macho:[],macro:48,made:[5,8,16,30,35,36,38,40,41,42,45,48,49,50],magnet:38,mai:[16,41,42,43,50],maim:16,main:[0,10,16,30,37,39,40,41,42,48,50],mainli:16,maintain:[5,16,37,41,49],mainten:[5,30,36,42,48,49,50],maintenc:8,major:[5,36,41],make:[5,6,8,10,11,13,15,16,17,26,30,35,36,38,39,40,41,43,45,46,48,49,50],make_and_start_left_wall_machin:[],make_and_start_right_wall_machin:[],make_generation_coroutin:[],make_test_spec:50,make_unique_name_based_on_start_at_funct:0,make_url:40,malevol:16,malform:9,man:[5,16],manag:[0,4,5,8,16,29,30,35,36,39,41,42,43,44,45,46,49,50],manageri:[],mandatori:9,maneuv:[16,17],mani:[5,8,11,16,28,36,38,39,40,41,42,43,45,46,48,50],manifest:[8,36,41,50],manipul:[40,42],manner:[8,30,42,43,48,50],manoeuvr:16,manual:[15,38,41,42,43],manufactur:[8,42],map:[8,10,16,17,29,35,36,40,41,42,43,49,50],marbl:[41,42],march:50,marcu:[],margin:[],mari:[6,42,50],mark:[11,15,16,30,35,38,39,41,42,43,45,48,50],markdown:43,marker:42,market:36,markup:[8,42],marshal:[16,17],marshal_entri:[16,17],marshal_readi:[16,17],martin:[5,41],marvel:50,mashup:[],mass:[5,16],massiv:[16,36],master:38,match:[16,41,50],materi:46,math:[30,48],mathemat:[16,36,41],mathematica:[],mathematician:36,mathwork:[],matlab:41,matplot:[],matplotlib:[],matrix:[],matter:[6,16,50],max:[26,42,43],max_index:9,max_name_len:[26,42,43],max_number_len:[26,42,43],maxim:16,maximum:[9,38],maximum_arrow_capac:[16,17],maxlen:0,mayb:[16,38,44,50],maywhil:[],mba:[],meali:8,mean:[5,8,9,16,26,27,36,37,38,39,40,41,42,43,44,46,48,49,50],meaning:[16,42],meaningless:50,meant:[8,16,36,46],meanwhil:[36,40,50],measur:[8,36,38,40],meat:16,mechan:[5,16,36,38,41,43,50],media:[],mediev:16,medium:[],meet:[16,37,42,50],member:[16,50],memori:[5,16,27,30,36,38,40,41,42,43,48,49,50],men:16,menac:16,mental:[16,36],mention:[39,42,46,50],mere:[41,42],merv:50,mesh_encryption_kei:16,mess:50,messag:[0,8,12,15,16,25,36,38,40,41,42,43,50],messi:42,met:[38,50],meta:50,metaclass:48,metal:38,metaphor:[16,36,39,50],metaprogram:[41,48,49],method:[0,4,6,8,9,10,16,25,26,31,35,36,37,38,39,41,43,44,46,50],method_1:41,method_2:41,metric:40,michel:38,micro:16,micromanag:[16,50],microsoft:[36,43],mid:[],middl:[5,11,12,27,39,42,43,44,46],middle_st:42,middle_state_entry_sign:42,middle_state_exit_sign:42,middle_state_readi:42,midwai:[30,48],might:[5,8,12,16,27,28,29,36,37,38,39,40,41,42,43,48,49,50],militari:[5,16],millisecond:[30,48,50],mimic:[],mind:[36,40,41,44],mine:41,minecraft:8,miner:10,mingu:[],mini:[],minim:[16,45,50],minimalist:50,minimum:[38,40],minion:50,minor:[],minut:[16,40,50],miracl:16,miro:[1,4,5,8,9,10,16,17,26,27,29,30,34,35,36,37,38,39,40,43,44,46,47,48,49,50],miros_rabbitmq:16,mirror:16,misbehav:50,miss:[16,41,42,46,49,50],mission:41,mistak:[16,41,50],mistakenli:16,misunderstood:36,mix:38,mixtur:42,mkdir:45,mnemon:[9,41,50],mobil:16,mock:50,mockup:[],mode:[4,38,50],mode_control:4,model:[8,36,38,39,41],model_control:4,moder:43,modern:[16,36],modifi:38,modul:[1,33,36,49],modular:50,modulo_bas:50,molten:38,momen:8,moment:[0,16,38,41,42,49,50],momentarili:42,momentum:36,mondan:[],monei:[5,36,43,50],mongol:7,monitor:[5,16,24,37,50],month:5,moor:8,moot:43,mordecai:5,more:[0,5,7,8,9,16,30,31,35,36,37,38,39,40,41,43,44,46,48,49,50],moreov:44,morn:40,most:[5,9,16,30,35,38,39,40,42,45,48,50],mostli:[37,41,42,45,50],motiv:50,mount:16,mous:[],mouse_click:41,mouse_click_evt:41,mousecoordin:41,move:[2,9,16,36,37,39,41,42,44,46,48,50],movement:[16,36,50],movi:[],mp4:[],much:[5,8,9,16,36,38,40,41,42,44,49,50],mud:16,mulishot:[],multi:[8,11,16,30,48],multi_shot_thread:[11,39,42],multipl:[16,30,31,37,38,40,41,43,45,48,49,50],multishot:[8,40,50],multitask:5,multithread:40,multivers:50,mundan:41,munger:50,must:[6,8,9,16,37,39,41,42,46,47,48],mutabl:41,mute:4,mutex:5,mutual:9,my_ev:41,my_event_with_payload:41,my_hook:42,mypayload:42,myself:[16,42,44,50],n_angl:[],n_mask:[],nag:44,nai:[],name:[0,5,6,8,9,11,14,16,17,26,31,35,36,37,38,39,40,41,43,44,45,46,48,49,50],name_for_sign:[6,26,42,43],name_of_item2:42,name_of_item_1:42,name_of_item_2:42,name_of_sign:42,name_of_state_name_of_ev:42,name_of_subclass:6,namedtupl:[40,41,42,50],namespac:39,nametupl:50,napkin:36,napoleon:16,narankhuu:[16,17],narantuyaa:[16,17],narrow:[],nassim:[35,44],nasti:[40,42,48,50],nativ:[],natur:[6,36,38,41,44,47,48],naviag:41,navig:[9,38],nearbi:50,neat:37,necessari:16,necessarili:[],neck:[16,50],need:[0,5,8,9,11,12,15,16,27,28,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],needlessli:[12,42],neg:50,neighbor:[],neither:[],neovim:5,nergui:[16,17],nervou:[16,50],ness:16,nest:[8,16,17,35,37,38,40,41,42,49],net:9,netscap:5,network:[6,9,15,17,36,42,43],network_error:40,network_error_retry_time_in_sec:40,networked_horse_arch:16,networkedactiveobject:16,networkedfactori:16,never:[5,16,30,36,38,39,41,42,48,50],new_machin:[],new_nam:50,new_named_attribut:6,new_request:38,newest:38,newli:[37,45],newlin:37,next:[7,8,16,17,18,19,20,21,22,23,28,34,36,38,39,40,41,42,43,44,46,47,49,50],next_gener:[],next_rtc:0,nice:[40,41,42,49,50],nich:36,nichola:[35,44],nietzsch:39,night:40,night_to_dai:40,night_to_night:40,no_ack:37,noam:45,nobl:41,nobodi:[16,50],node:[16,37,40,41,49],nois:[],noisi:16,nomin:40,non:[10,30,42,43,48,50],nondetermin:5,none:[0,6,8,9,10,16,17,35,37,38,39,40,41,42,44,46,49,50],nonexist:50,nonsens:37,noob:[],normal:4,norman:5,north:16,not_rain:40,not_raining_exit_sign:40,not_raining_init_sign:40,not_raining_st:40,not_wait:[16,17],note:[16,37,40,42,44,50],notebox:[],noth:[0,4,5,8,38,39,40,41,42,46,47,50],nothing_angl:[],nothing_at_row:[],nothing_mask:[],notic:[8,15,16,30,31,36,38,39,40,41,42,43,44,48,49,50],notifi:[16,50],notion:[16,36,41],notit:[],now:[5,9,12,15,16,35,37,38,39,40,41,42,43,44,45,46,48,49,50],nsa:42,nuanc:42,nuclear:38,number:[6,8,11,15,16,26,27,31,35,38,41,42,43,46,48,50],numer:16,numpi:38,nutshel:50,nvu8m8a73jg:[16,37],oadp1sh69j:[],obei:16,obj:6,object:[1,5,6,8,9,11,15,16,26,27,28,29,30,31,35,36,38,39,40,41,43,44,48,49,50],oblivion:50,obscur:5,observ:44,obtain:[15,37,42,43,48],obviou:[16,35],obvious:[],occur:[8,9,16,27,30,31,36,38,39,40,41,42,43,46,48,50],occurr:[],od647c:[],oddli:50,off:[10,12,13,16,38,39,40,41,42,49,50],off_entri:38,off_press:41,offer:[37,42,50],offic:[16,17],officer_lur:[16,17],offset:50,often:[8,16,36,38,41,42,50],oha:[16,17],oha_1:16,old:[0,16,27,36,40,42,43,46,49,50],old_left_machin:[],old_machin:[],old_right_machin:[],oldest:[8,38,39,42],onc:[6,8,9,11,16,17,27,38,39,40,41,42,43,45,46,48,50],one:[0,5,6,8,9,11,12,13,15,16,18,24,30,31,36,37,38,39,40,41,43,45,46,47,48],onedcellularautomatawithanglediscoveri:[],onedcellularautonomata:[],ones:49,oneshot:50,onli:[0,5,9,11,14,16,29,31,34,36,37,38,39,40,41,42,43,44,45,46,48,50],onlin:42,onplayerreadi:[],onplayerstatechang:[],onreadi:[],onstatechang:[],onto:[0,5,8,15,16,35,36,37,38,39,40,41,42,43,45,50],onyoutubeiframeapireadi:[],onyoutubeplayerapireadi:[],oop:[36,44],open:[10,36,38,40,41,42,45,50],open_weather_map_city_detail:40,openweathermap:40,openweathermapcitydetail:[],oper:[5,8,16,30,36,38,40,42,46,48,50],oppon:16,opportun:[16,48,49,50],oppos:[5,16,36],opposit:[5,16],optim:[],option:[8,9,16,42,45],optionalpayload:41,orang:[],orb:50,order:[8,16,17,38,40,43,44,50],ordereddict:6,ordereddictionari:[26,42,43],ordereddictwithparam:6,org:40,organ:[16,38,43,49,50],orient:[36,38,40,41,42],origin:[0,8,12,16,36,38,42,44,48,49,50],orthogon:[4,8,16,36,40,50],oscil:[16,48],oscilloscop:50,other:[0,5,8,9,11,15,16,17,26,27,28,30,35,36,37,38,39,40,41,45,46,47,48,49,50],other_advance_war_cri:[16,17],other_archer_nam:16,other_arrival_on_field:16,other_inner_most:42,other_ready_war_cri:[16,17],other_retreat_ready_war_cri:[16,17],other_retreat_war_cri:[16,17],other_skirmish_war_cri:[16,17],otherhorsearch:[16,17],otherwis:[8,9,16,28,36,38,40,41,42,43,44,49],our:[0,5,9,10,12,13,28,29,30,35,36,38,39,40,41,42,43,45,46,47,48,49,50],ourselv:[16,38,40,42],out:[0,5,6,8,9,10,13,16,17,27,29,35,36,37,38,39,41,42,43,44,45,46,49,50],out_of_arrow:[16,17],outag:40,outcom:5,outer:[8,11,12,16,27,38,39,41,42,43,46,50],outer_st:[38,41,42],outer_state_broadcast:42,outer_state_entry_sign:[41,42],outer_state_exit_sign:42,outer_state_hook:[41,42],outer_state_init_sign:[41,42],outer_state_reset:42,outer_state_retri:41,outer_state_send_broadcast:42,outermost:[41,42,50],outmost:[],output:[0,8,9,15,16,26,27,28,29,31,35,38,39,40,41,42,44,46,48,49,50],outsid:[8,9,12,13,16,17,30,36,38,39,40,41,42,44,46,48,50],outsourc:[],outward:[8,9,16,38,41,42,50],outwardto:[],outweigh:50,oval:50,oven:[10,38,41],oven_off:6,over:[0,4,5,8,9,16,28,29,35,36,37,38,39,41,42,43,44,45,49,50],over_off:6,overal:16,overemphas:36,overflow:[37,38],overli:42,overload:[38,41],overrid:38,overtak:[],overwhelm:[16,39],overwrit:[38,43],overwritten:[9,39],owm:40,own:[2,5,8,16,30,36,38,39,40,41,44,45,48,49,50],oxymoron:41,p27:[],pack:[5,16,35,41,42,46,49,50],packag:[8,16,36,41,42,50],packet:[],pact:[],page:[5,16,33,35,36,40,41,44,45,50],paglia:46,pai:[4,5,16,35,38,39,41,42,50],paid:5,pain:[5,45],paint:50,pair:50,pale:5,palett:41,pallet:41,pantri:38,paper:[8,30,36,38,39,42,46,48],paradigm:39,paradox:16,paragraph:[46,50],parallel:[36,39,42,43],paramet:[6,37,50],parameter:50,parameteriz:[],parametr:16,paramount:16,parent:[8,9,16,17,35,37,38,40,41,46,49,50],parent_callback:[8,49],parent_state_of_this_state_method:42,parentnod:[],pariti:6,pars:50,parsimoni:36,part:[0,4,9,10,11,16,17,30,36,37,38,39,40,41,42,44,45,46,48,49,50],partial:[41,42],particip:[16,43,50],particular:[5,41,42,43],particularli:[44,50],partnership:41,pass:[6,8,12,16,17,30,36,37,38,39,41,44,46,48,50],passphras:45,password:45,past:[15,36,41,42,43,44],patch:41,path:[8,9,16,40],pathlib:[16,40],pathwai:[16,42],patient:50,pattern:[4,7,8,16,33,36,37,39,40,41,42,46,47,50],paus:[],payload:[6,8,16,17,31,35,38,40,43],payment:36,pcolormesh:[],pdb:[28,42,43],pdf:[40,50],peachi:[29,42,43],pedant:5,pencil:42,pend:[0,6,16,29,42,43,46,49,50],pending_on_piston:38,pending_on_pistons_timeout:38,pending_optimal_condit:38,pentagon:5,peopl:[5,16,30,36,38,41,48,50],pepper:[16,39,41,50],per:[8,16,17,39,40,42,47,50],percent:[5,16,17,40,50],percol:41,percul:[],perfect:[16,42],perfectli:[],perform:[5,9,16,17,36,38,39,40,41,42,44,45,48,49,50],peril:5,period:[0,8,11,12,16,17,38,39,40,42,50],peripher:[16,36,40],permiss:[44,45],permit:[16,50],permut:[],pernici:[],perpetu:[],persist:50,person:[16,30,36,41,44,47,48,49,50],perspect:36,peter:[16,50],pgn:[],phase:[42,46,50],phenomenon:16,philosoph:[36,44],philosophi:50,phoenix:46,phrase:50,phsysic:[],physic:[8,38,50],pic:37,pick:[5,16,30,48,50],pickl:6,pico:45,pictori:[],pictur:[15,16,35,36,37,40,41,42,43,46,47,50],piec:[5,30,46,48,50],pierr:[5,35],pigment:[],pika:[37,45],pilot:5,pin:[40,50],pioneerrequest:42,pioneerrequestspec:42,pip3:37,pip:[34,50],pis:[],piston:38,piston_1:38,piston_:38,piston_act:38,piston_manag:38,piston_numb:38,piston_readi:38,piston_slam:38,pitch:41,pivot:50,place:[0,4,8,9,13,15,16,29,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],placement:41,plai:[4,16,42,48,50],plain:[8,16,41],plain_text:37,plaincredenti:37,plan:[16,38,40,46,50],plane:5,planet:5,plant:[36,40],plasma:38,plastic:[],plate:[41,50],platform:[37,50],playbook:45,player:[],player_api:[],playerstatu:[],playvideo:[],pleas:40,plenti:16,plod:[],ploi:[],plot:[],plt:[],pluck:16,plugin:[16,36,41,42],png:[],pocket:50,point:[5,8,9,15,16,17,28,29,36,38,43,46,48,50],pointless:[36,50],poke:40,pole:38,polici:[16,38],polish:[],poll:38,polling_ent:38,polling_init:38,polling_process:38,polling_time_out:38,polling_time_out_hook:38,polyamor:38,poni:16,pool:[8,38],poorli:[],pop:[0,5,8],popleft:[],popul:9,popular:[36,40,41],port:[5,8,36,37,38,39,40,42,45,50],portabl:50,portal:50,portion:[],pose:42,posit:[38,50],possess:44,possibl:[9,16,36,37,38,41,42,43,45,48,50],post:[0,6,8,12,13,16,27,35,38,40,41,43,46,49,50],post_act:4,post_def:[27,28,38,39,42,43],post_fifo:[0,8,10,11,12,16,17,27,35,37,38,39,40,41,42,43,44,46,49,50],post_id_1:0,post_id_2:0,post_lifo:[8,11,38,40,41,42,50],postul:5,potato:50,power:[5,16,36,38,41,43,50],practic:[5,8,9,35,36,38,40,41,44,50],praction:[],practition:[36,38],pragmat:[],pratic:[],pre:[8,16,29,42,43,49,50],pre_time_sec:50,preced:[],precis:[16,48,50],predatori:[],predefin:[41,50],predetermin:[16,38,50],predica:16,predict:[],preemption:5,preemptiv:5,prefer:[16,50],prefix:16,preform:50,prei:16,preliminari:50,prematur:16,prepar:[16,42],prepend:50,prepend_trace_timestamp:50,preprocessor:[48,49],present:[5,8,16,36,38,42,46,50],press:[15,36,42,43,50],pressur:[13,38,40,42],presum:50,pretend:[16,38,39,50],pretti:[16,27,28,42,43,44,45,49,50],prev:[7,18,19,20,21,22,23,34,36,38,40,41,42,43,47,50],previou:[4,16,39,40,41,42,46,49,50],previous:[16,39,46],previous_gener:[],price:[39,40,50],prim:0,prime:[16,38],princip:46,principl:[15,42,43,47],print:[0,4,6,8,10,16,17,26,27,28,29,35,37,38,39,40,41,42,43,46,48,49,50],print_msg:50,print_payload:41,print_str:41,printer:[27,42,43],prion:[],prior:[6,8,12,35,37,38,39,40,42,48],priorit:[],prioriti:[0,5,8,16,35,42,50],priorti:[0,8],privat:[36,45],privileg:39,probabilist:[30,42,48],probabl:[15,16,38,39,41,42,43,50],problem:[5,8,16,29,30,36,38,40,41,42,43,44,45,48,49,50],proce:[16,41,50],procedur:45,proceed:48,process:[5,6,8,9,11,13,16,17,27,30,36,37,38,39,40,41,42,43,45,46,48,49,50],process_a_gener:38,process_a_specif:38,process_b_gener:38,processing_count:38,processing_entri:38,processing_exit:38,processing_init:38,processing_pol:38,processor:[5,8,9,16,27,36,37,38,39,40,42,43,44,46,49,50],produc:[8,16,24,36,38,39,40,41,48,50],producer_192:37,producer_out:37,producer_outer_b:37,producer_outer_init:37,product:[36,38,40,41,43,50],profession:38,profil:[],profit:5,program:[4,5,8,9,10,15,16,26,28,29,30,36,38,39,40,41,42,43,45,46,48,49,50],programat:43,programm:[16,38,50],programmat:[],progress:50,prohibit:50,project:[5,16,31,36,38,40,42,43,50],promis:36,prompt:45,proof:[18,19,20,21,22,23],propag:[38,41,50],proper:40,properli:[8,16,41,42,49],properti:[8,16,36,37,48],prophet:35,propos:38,proprietari:36,protect:[5,16,30,48,50],protoc:[],protoco:[],protocol:[40,48,50],prototyp:[38,40,41,50],protractor:[],prove:[16,50],proven:[5,50],proverb:[],provid:[0,5,6,8,9,11,16,26,35,36,37,38,40,41,42,43,45,46,48,49,50],pseudo:[],pseudost:[8,38,41,42,50],psycholog:[43,44],pub:[0,35,37,42,45,50],pub_sub_exampl:41,publish:[0,5,8,16,35,36,37,40,45,50],publish_bb:35,publishing_ao:42,pull:[5,6,16,17,36,39,40,41,44,46,50],puls:[38,50],pump:[16,38,39],purchas:5,purpl:[],purpos:[24,37,38,42,45,50],pursu:[5,16],pursuit:44,push:[0,16,38,42,44,49,50],put:[0,16,17,30,38,39,40,41,42,43,44,48,50],puzzl:50,pycrypto:37,pydotenv:16,pyplot:[],python3:[42,50],python:[4,5,8,16,26,30,34,36,37,38,40,41,43,44,45,48,49,50],qai9iicv3fkbfruakrm1gh8w51:[16,37],quad:50,quantum:39,quarri:16,quarter:16,queri:[4,40,42,46,50],query_api:40,query_weath:40,query_weather_init_sign:40,question:[15,16,18,19,20,21,22,23,35,36,41,42,43,49],queu:[4,27,28,35,36,37,38,39,40,41,42,43,44,46,49,50],queu_depth:[],queue:[0,8,13,16,35,37,38,39,40,41,42,45,46,50],queue_bind:37,queue_declar:37,queue_depth:42,queue_typ:[0,42],quick:[33,36,41,50],quicker:[],quickli:[16,36,39,41,43,50],quickstart:50,quieter:16,quit:[16,36,37,38],quiver:16,quora:[],quot:[5,38],rabbit123:45,rabbit567:16,rabbit:[16,37,38,45],rabbit_guest_us:16,rabbit_heartbeat_interv:16,rabbit_instal:45,rabbit_nam:45,rabbit_password:[16,37,45],rabbit_port:16,rabbit_producer_192:37,rabbit_us:[16,37],rabbitfactori:16,rabbitmq:[16,36,41,42],rabbitproduc:37,race:[5,16,30,48],radar:36,rage:41,raid:[],rain:[16,40],rais:[8,9,50],ran:[24,36,37,38,39,40,42,46,49,50],randint:[16,17,42],random:[16,17,37,38,40,42],random_numb:38,randomli:50,rang:[5,16,38,40,50],rank:16,rap:50,rare:50,raspberri:[16,24,37,40,45,50],rate:[5,38],rather:[8,16,38,39,41,42,43,50],ratio:[],ravel:[],raw:[],raw_weather_lookup_dict:40,raw_weather_lookup_list:40,reach:[8,16,38,39,42,50],reachabl:37,react:[4,8,12,16,27,38,39,40,41,42,43,46,49,50],reaction:[8,13,16,38,39,42,46,50],reactiv:[36,38,42,46],reactor:38,reactor_on:38,reactor_on_entri:38,reactor_on_init:38,reactor_on_prim:38,reactor_on_time_out:38,read:[5,8,9,16,26,27,30,36,38,39,40,41,42,43,45,46,48,49,50],read_fil:40,read_file_entry_sign:40,reader:[],readership:36,readi:[16,17,28,38,39,40,42,43,44,50],real:[5,16,36,37,38,40,50],realiti:[16,44],realiz:41,realli:[5,16,36,38,40,41,42,44,46,50],rearm:39,reason:[6,16,31,36,37,40,41,42,43,45,46,50],rebuild:[28,42,43],recal:[8,13,27,38,39,40,43],receiv:[8,16,26,27,35,37,38,39,40,41,42,43,44,45,46,50],receiving_entri:38,receiving_receiv:38,recent:[38,40],reciev:[],recip:[33,36,39,43],recipi:50,reckless:36,recogn:[16,39],recommend:[5,36,37,40,42,43,45,46,48],reconnect:37,reconsid:[38,49],reconstruct:5,record:50,rectang:[],rectangl:[16,40,41,42,44,46,50],rectangular:41,recurs:[16,38,39,41,50],red:[10,40,41,42,50],red_light_off:10,red_light_on:10,redefinit:36,redesign:38,redraw:[38,42],reduc:[8,16,40,43,50],reduct:[],redund:[16,50],reef:[],ref:[],refact:8,refactor:[16,36,38,40,41],refer:[7,9,16,18,19,20,21,22,23,27,30,35,36,37,38,39,40,41,42,43,45,46,47,48,50],referenc:[8,9,15,16,36,42,43,50],refil:16,reflect:[8,16,26,33,36,38,39,42,46],reflection_sign:[26,42,43],refocu:16,reform:41,refrain:[],refresh:50,regain:36,regard:[36,38,39,50],region:[8,16,38,41,50],regist:[37,42],register_live_spy_callback:[37,42],register_live_trace_callback:[37,42],register_par:[42,49],register_signal_callback:[42,49],registr:[42,49],registri:0,regress:[16,29,42,43,50],regroup:16,regular:42,reject:36,rejoic:50,rejoin:50,rel:[8,50],relai:[40,41,50],relat:[5,8,9,16,37,38,39,41,42,49,50],relationship:[8,9,41,42],relax:[38,50],releas:[5,8,36,38,41,48,50],relentlessli:[],relev:38,reli:[16,38,50],reliabl:50,reliev:[13,42],religi:5,relinquish:50,reload:16,reluct:[41,43],remain:[16,38,41,46,50],remark:[5,16],remedi:[],rememb:[5,16,38,39,41,42,44,46,50],remidi:8,remind:[8,16,40,42,45,50],reminder_pattern_needed_1:38,reminder_pattern_needed_2:38,remov:[16,29,37,38,40,41,42,43,48,49,50],renam:49,render:[16,41],renderexplorewidget:[],rendit:39,reorgan:16,repeat:[8,11,38,40,41,42,46,49,50],repeatedli:39,repetit:[16,50],replac:[15,16,37,42,43,45,50],replic:[15,42,43],repo:2,report:[38,50],repost:[13,42],repres:[8,9,15,16,38,39,41,42,43,46,50],represent:41,reproduc:[30,48,50],request:[0,38,40,42,50],request_city_detail:40,request_details_for_c:40,requestdetailsforcitypayload:40,requir:[6,9,16,30,35,36,38,39,40,41,42,45,46,48,49,50],reset:[41,42],resetchart:46,resettact:16,resettl:[],resili:40,resist:16,resolut:16,resolv:40,resourc:[5,16,40],respect:[16,50],respond:[8,16,17,35,39,42,43,46,49,50],respons:[16,38,42,46,50],rest:[16,37,38,39,41,42,46],restart:0,restor:46,restructuredtext:50,resubscrib:37,result:[16,17,28,29,30,36,37,38,39,40,41,42,43,46,48,49,50],resulting_funct:49,resurrect:46,ret_sup:6,ret_super_sub:6,ret_zz:6,retir:5,retreat:[16,17],retreat_ready_war:16,retreat_ready_war_cri:[16,17],retreat_war_cri:[16,17],retri:41,retriev:[],retry_after_network_error:40,return_st:[38,42,50],return_statu:[10,16,17,25,26,35,38,40,41,42,43,44,46,49,50],returncod:6,returnstatussourc:1,reus:38,reusabl:38,reveal:[5,16,44],rever:50,revis:45,revolt:[],rewind:46,rich:[5,42,50],richard:47,richest:5,richli:[],rid:[36,40,50],ride:[16,35,40],ridg:[],ridget:[],rig:[],right:[5,8,16,37,38,40,41,44,49,50],right_wal:[],rightfulli:[],rigid:[38,41],rigor:[5,16,50],ring:[8,27,38,42,43,50],risk:16,ritual:50,rlock:48,robot:[36,40],robust:[16,36,37],roll:[41,42],roman:[],ronach:8,room:[27,41,42,43],root:[],rosetta:50,rotat:[16,38],rough:[40,50],roughli:[5,50],round:[40,41,42,50],rout:[16,37,45],routin:[9,38,49],routing_kei:37,row:49,row_to_check:[],rpc:45,rst:[],rtc:[0,5,8,9,27,38,41,42,43,46,50],rubbl:[],rubi:50,rudimentari:[],rule:[5,8,16,30,35,36,40,42,46,48,50],rule_30:[],rule_30_black_walls_200_gener:[],rule_30_white_walls_100_generations_width_30:[],rule_30_white_walls_200_gener:[],rulebook:[],ruler:[],run:[0,4,5,8,9,10,15,16,24,25,27,28,29,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],run_anim:[],run_ev:0,runtim:42,rush:[],ruthlessli:44,rx_routing_kei:16,s11:[4,44],s11_state:44,s1_state:44,s211:4,s21:[4,9,44],s21_state:[25,42,44],s2_state:[25,42,44],s_state:[25,42,44],safe:[1,5,7,16,30,38,41,44,50],safeti:[16,42,48],sai:[5,16,38,39,40,41,42,46,49,50],said:[36,38,42,46,50],sake:42,salari:5,salt:39,same:[0,4,5,6,7,9,11,12,16,26,29,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],samek:[5,8,9,16,36,38,39,41,42,44,49,50],sampl:[38,40,50],sandwich:[],saskatoon:40,satisfact:[44,50],satisfi:50,saturn:5,sausag:40,save:[11,16,38,39,42,43,45],savefig:[],saw:[16,36,40,42,46],scaffold:[],scalabl:45,scale:[36,38],scan:[16,36,40,41,46],scare:[16,17],scari:48,scenario:50,scene:50,scheme:[16,38,42],scienc:[38,41],scientif:[44,47],scimitar:[16,17],scipi:[],scope:37,score:5,scotti:45,scrambl:50,scratch:16,screen:[4,16,28,37,40,42,43],screw:[30,48],scribbl:[8,16,17,25,35,38,41,44,46,50],script:[37,45,50],scroll:50,sculpt:16,search:[8,9,12,33,38,39,41,42,46,49,50],search_for_super_sign:[26,27,28,35,37,38,39,41,42,43,44,46,49,50],season:16,sec:[16,17],second:[8,12,16,17,31,36,38,39,40,41,42,43,44,49,50],secondari:8,secondli:[],secret:[16,45,50],secretli:38,section:[4,7,16,36,39,40,41,42,45,46,49,50],secur:[16,45],see:[0,4,5,6,8,14,15,16,25,26,30,31,35,36,37,38,39,40,41,43,45,46,48,49,50],seed:38,seek:44,seem:[5,16,30,36,37,38,42,46,48,49,50],seemingli:48,seen:[6,8,16,38,40,41,42,45,46,48,50],segment:36,select:[15,42,43,50],self:[6,9,10,16,17,37,38,39,40,41,42,45,48,50],selfpayingtoasteroven:10,sell:[],semant:[36,38,39,41],semaphor:5,semblanc:16,send:[4,6,8,15,16,36,38,39,40,41,42,43,44,45,46,49,50],send_broadcast:42,senior:[16,17],senior_advance_war_cri:[16,17],senior_retreat_war_cri:16,senior_skirmish_war_cri:[16,17],sens:[16,37,39,40,41,42,43,44,45,46,50],senseless:39,sensibl:[16,36,42],sensit:[],sensor:[16,38],sent:[8,16,35,37,38,39,40,41,42,46,50],sentenc:[16,41,50],seoc:[],separ:[5,16,37,38,39,40,41,42,50],seper:8,sequenc:[8,9,15,16,31,35,37,38,40,43,44,50],sequence_diagram:41,seri:[36,46],serial:6,seriou:[5,50],serious:5,serv:[16,40,41,42,50],server:[37,38,40,45,50],servic:[5,8,40],session:[28,42,43],set:[0,8,9,11,16,36,38,39,40,41,42,48,50],set_arrai:[],set_aspect:[],set_ticks_posit:[],set_titl:[],set_trac:[28,42,43],set_xticklabel:[],set_yticklabel:[],setter:[],settl:[8,9,12,16,38,41,42,46,50],setup:[16,40,45],seventi:[],sever:43,shadow:9,shake:50,shallow:50,shalt:46,shape:49,share:[5,8,9,16,26,30,35,36,38,39,40,41,42,43,48,50],she2:41,she:[41,50],sheet:16,shelf:38,shell:[16,41,45],shelv:38,shift:[27,42,43,50],shine:38,ship:[16,50],shoot:[16,41,49,50],shop:50,shortcode1:[],shortcode2:[],shorten:[],shorter:16,shorthand:[16,41,44,50],shortli:[38,41,42,45],shot:[8,11,12,16,17,38],should:[5,6,8,11,12,16,29,35,36,37,38,39,40,41,42,43,45,46,49,50],shoulder:[36,50],shouldn:[29,41,42,43,50],shout:16,show:[0,8,16,35,36,37,38,39,40,41,42,45,46,48,49,50],shown:[4,5,50],shrink:41,shut:[37,41,46,50],shutdown:43,side:[5,16,41,42,50],sight:[],signal:[0,1,4,8,9,10,11,12,13,16,17,25,26,27,31,35,37,38,39,40,41,44,46,49,50],signal_callback:[8,49],signal_nam:[0,6,26,40,41,42,43],signal_numb:[26,40,42,43],signal_that_is_def:[13,42],signalsourc:[1,26,42,43],signatur:[37,39,42,49,50],signifi:41,signific:[16,30,48],significantli:[5,36,37],silo:[],similar:[16,36,38,41,42,49,50],similarli:38,simpl:[15,16,18,27,30,36,37,38,40,41,42,43,45,47,48,49],simple_fsm_2:41,simple_state_10:42,simple_state_11:42,simple_state_12:42,simple_state_13:42,simple_state_14:42,simple_state_15:[],simple_state_3:42,simple_state_5:42,simple_state_6:42,simple_state_7:42,simple_state_8:42,simple_state_9:42,simpleacyncexampl:[],simpleasyncexampl:[],simpler:[16,42],simpli:[5,30,38,41],simplic:[15,38,42,43],simplif:16,simplifi:[5,38,40,41,50],simul:[38,50],sinc:[5,6,9,12,15,16,27,35,36,37,38,39,41,42,43,44,45,46,47,48,50],singl:[7,16,36,38,39,41,42,50],singleton:[0,8,26,42,43],singular:[],sissi:[],sisyphean:[],sit:[8,16,42,50],site:[9,45],situat:[13,16,25,30,38,42,44,48,50],sixti:16,size:[38,40,50],sketch:[8,16,29,36,40,41,42,43],skill:16,skip:[16,37,38,42,46],skirmish:[16,17],skirmish_ammunition_low:[16,17],skirmish_entri:[16,17],skirmish_exit:[16,17],skirmish_officer_lur:[16,17],skirmish_other_squirmish_war_cri:[16,17],skirmish_retreat_ready_war_cri:[16,17],skirmish_second:[16,17],skirmish_senior_squirmish_war_cri:[16,17],skirmish_war_cri:[16,17],sky:50,slai:16,slam:38,slaughter:16,slave:42,sleep:[10,16,35,37,38,39,40,41,42,44,46,48,49,50],slide:39,slight:16,slightli:[16,41,42,50],slip:50,slot:[38,48],slow:[16,42,50],slower:8,slowest_tim:38,slowli:[16,50],small:[15,16,36,38,39,42,43,44,50],smaller:[16,41,42],smallest:[41,43],smart:[],smarter:16,smash:[],smear:50,smell:50,smile:50,smurf:16,snail:[],snap:[16,50],snare:16,snippet:[16,39,41,50],snoop:16,snoop_kei:16,snoop_scribbl:16,snoop_spy_encryption_kei:16,snoop_trace_encryption_kei:16,snow:40,social:47,societi:50,sock_dgram:37,socket:[37,42],softwar:[5,8,16,35,36,38,40,42,45,49,50],soil:[],soldier:16,solid:41,solips:50,solipsist:50,solo:[],solut:[36,38],solv:[8,30,36,37,38,40,41,42,48,49],solver:[],some:[5,8,12,15,26,30,35,36,38,39,40,41,42,43,44,46,47,48,49,50],some_event_the_system_has_never_seen:[],some_example_st:[26,42,43],some_st:[41,50],some_state_funct:50,some_state_to_prove_this_work:50,somebodi:39,somehow:[16,50],someon:[16,30,35,38,39,40,41,42,43,48,50],someth:[0,5,8,16,26,29,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],something_els:42,sometim:[9,16,17,30,48,50],somewai:[],somewhat:[36,37],somewher:[16,40,50],soon:[16,37,38],sorri:5,sort:[16,35,38,39,41,42],sound:[39,50],sourc:[2,8,9,15,16,36,39,41,43,44,45,50],source_st:41,space:[9,16,36,38,39,42,50],span:[37,50],spare:42,spawn:50,speak:[8,12,39,42],spec:[18,19,20,21,22,23,38,41,50],special:[4,16,35,38,39,41,46,50],specialist:41,specif:[15,16,27,28,29,36,38,39,41,43,44,46,48],specifi:[0,38,41,42,50],specifici:[],speed:[5,16,36,38,40,42],spell:49,spend:[5,16,36,41,50],spent:[5,16,36,41],sphere:38,spike:50,spinkler:[],spirit:[42,50],spit:37,split:[16,46,50],spoil:16,spooki:[],sporat:38,spot:[8,16,27,42,43,50],sprai:[],spread:[16,36],spreadsheet:16,sprei:[5,35],sprinker:[],sprinkler:36,sprinkler_heart_beat_sec:40,sprinkler_high_level:[],sprinkler_off:40,sprinkler_off_entry_sign:40,sprinkler_off_init_sign:40,sprinkler_on:40,sprinkler_on_done_wat:40,sprinkler_on_entry_sign:40,sprinkler_on_exit_sign:40,sprinkli:[],spruce:37,spy:[0,4,8,16,24,25,27,28,35,38,39,41,44,46,49,50],spy_callback:[37,42],spy_ful:[39,46],spy_lin:50,spy_liv:37,spy_of_trac:50,spy_on:[4,10,11,12,14,16,17,25,38,39,41,42,43,44,46,49,50],spy_on_buzz:50,spy_on_heater_off:50,spy_on_heater_on:50,spy_on_light_off:50,spy_on_light_on:50,spy_or_trac:50,spy_queue_nam:37,spy_result:37,squar:[31,38,42,43,44],squirrel:46,squish:[],src:[],ssaw:[],ssh:45,ssl:[],sssub:[],stabil:50,stabl:50,stack:37,stadium:[],staff:5,stage:[13,16,38,42,50],stai:[16,38,42,50],stair:50,staircas:50,stamp:[31,38,42,43,50],stand:[42,46,49,50],standard:[15,34,36,37,41,42,43],star:[38,41,50],stare:[],start:[0,8,9,10,16,17,27,28,30,31,33,35,36,37,38,39,41,43,44,46,48,49,50],start_at:[0,9,10,15,16,17,29,31,35,37,38,39,40,41,42,43,44,46,49,50],start_consum:37,start_exampl:42,start_thread_if_not_run:0,start_tim:50,startchart:[13,42],starting_st:38,starting_state_funct:9,startup:50,starvat:5,stash:[16,17],statchart:8,statchmachin:50,state:[0,4,5,6,8,9,10,11,12,13,14,15,16,17,25,27,30,31,35,36,37,38,39,40,46,48,50],state_at:[],state_chart_object:[],state_fn:[14,42,43],state_method_nam:42,state_method_templ:[8,42,49],state_nam:[0,14,16,17,41,42,43,50],state_recipe_15:[],state_return:6,state_to_transition_to:42,statecchart:[],statechart:[0,4,5,6,7,8,9,10,12,14,15,16,24,25,29,30,36,38,39,40,43,44,46,48,50],statechart_object:[],statehandl:42,stateless:42,statemachin:[4,24,37,41,42,50],statement:[4,16,42,46,48,50],statemethod:[14,42,43],staticmethod:[37,40,41,42,50],station:40,statocol:40,statu:[10,11,12,16,17,25,26,35,37,38,39,40,41,42,43,44,46,49,50],steadi:38,steam:38,stencil:36,step:[8,9,16,38,39,43,44,45,50],stephen:[],stick:[16,50],still:[0,5,16,36,38,39,41,42,44,49,50],stimul:[8,46],stimulu:38,stitch:[],stochast:38,stock:[],stone:50,stop:[0,8,16,17,37,38,39,40,41,46,50],stop_active_object:0,stop_consum:37,stop_fabr:[],stopper:48,store:[5,37,38,39,40,42,50],stori:[5,15,16,28,36,39,41,42,43,46],str:[16,17,26,38,40,41,42,43,50],straight:[30,36,41,42,48],straightforward:[37,38,45],strand:16,strang:[16,39,42,44,49,50],strateg:16,strategi:[5,16,30,37,39,42,48],straw:[],stream:[4,6,16,37,42,50],stretch:[],strftime:[38,42,50],strike:38,string:[6,8,9,14,26,29,37,38,41,42,43,49,50],strip:[16,29,42,43,50],strip_trac:37,stripped_spec:[],stripped_target:[16,29,42,43,50],stripped_trace_result:[16,29,42,43,50],stroke:16,strong:[16,36],strongli:[5,38],structur:[1,8,16,35,36,38,39,40,42,44,45,46,49,50],struggl:39,stub:[],studder:[],studdler:[],studi:[16,50],studio:[],stuff:[41,42,50],stupid:16,stupidli:16,stutter:36,style:[8,42,50],sub:[0,30,37,42,45,48,50],sub_row_to_check:[],subclass:[6,38,41,50],subclassed_ao1:41,subclassed_ao:41,subdesign:42,subject:[],suboptim:38,subordin:16,subplot:[],subscrib:[0,5,8,16,35,36,37,40,45],subscribing_ao:42,subscript:[0,8,16,40,41,42],subservi:50,subset:[5,8,16],substat:[8,9,16,38,41,42],subsubclassed_ao2:41,subsystem:50,subtl:[30,38,48],subvers:50,succe:45,succeed:37,success:[5,38],successfulli:16,suck:16,suddenli:36,sudo:45,sued:[],suffici:16,suffix:[],suggest:[40,42],suicid:[],suit:50,sum:16,summar:[37,43,46],summari:46,summer:40,summer_to_dai:40,summer_to_night:40,summer_to_summ:40,summer_to_wint:40,sun:[],sunk:41,sunni:[],sunris:40,sunset:40,superclass:42,superior:16,supernatur:50,superst:[8,38,41,50],suppli:16,support:[0,9,15,36,37,38,41,42,43,45,50],suppos:[15,16,31,38,42,43,44,48,49,50],sure:[16,17,37,38,40,41,42,49,50],surpris:[38,47,49,50],surround:[5,16],surviv:16,suspens:50,sustain:16,svg:[41,42],swap:5,swarm:16,swell:[],swing:[16,38],symmetr:16,synanoum:[],synchron:[16,36,38,41,42],synonym:[8,41],syntact:[16,38,48],syntax:[26,36,38,39,40,42,43,45,48,49,50],synthes:[],sys:40,system:[5,6,8,9,12,15,16,27,28,30,35,36,38,39,40,41,43,45,46,48,49,50],t_question:44,tabl:[],tabular:[],tack:[],tackl:40,tactic:17,tag:50,tail:[27,38,42,43,46],taint:41,take:[0,5,8,16,36,37,38,39,41,42,44,46,50],takeawai:[],taken:[8,16,36,42],taleb:[35,44],talk:[5,16,36,38,39,41,42,43,45,50],tar:5,tara:50,target:[8,9,12,16,28,29,36,38,41,43,44,48,50],target_st:41,targetandtolerancespec:50,tart_at:[15,42,43],task:[0,5,16,30,42,46,50],task_ev:0,tatechart:[],taught:5,taxat:16,tazor:[15,28,29,31,39,42,43],tazor_oper:[28,39,42,43],tc1:49,tc2:49,tc2_s1:[],tc2_s2:[],tc2_s3:[],teach:5,team:[16,35,36,37,41,43],teammat:[16,43],tear:50,technic:[5,41,42,44,50],techniqu:[0,8,16,37,38,41,42,48,50],technlog:[],technolog:[5,36,37,50],tediou:50,tell:[5,9,15,16,28,36,38,39,40,41,42,43,45,46,50],tem:[],temp:[9,10,11,12,16,17,25,38,39,40,41,42,44,46,48,49,50],temp_max:40,temp_min:40,temperatur:[8,38,40,50],templat:[8,41,42,45],tempor:36,temporari:[6,30,40,43,48,50],tempt:[16,50],ten:[16,40,45],tend:[41,42],tension:50,term:[8,27,36,40,41,42,43,50],termin:[4,15,27,37,38,39,42,43,49,50],terminolog:37,terrac:50,terrain:16,terribl:16,test:[0,5,9,10,15,16,28,29,30,33,34,36,37,38,40,44,45,48],test_baking_buzz_one_shot_tim:50,test_buzz_ev:50,test_buzz_tim:50,test_toaster_buzz_one_shot_tim:50,test_typ:50,testabl:50,text:[5,8,15,41,42,43],textil:[],th1:48,th2:48,than:[5,8,10,15,16,17,24,30,35,37,38,39,40,41,43,48,49,50],thankfulli:[16,50],thei:[4,5,8,9,12,15,16,17,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],theirs:[16,50],them:[5,6,8,9,11,12,16,17,35,36,37,38,39,40,41,42,44,45,46,48,49,50],theme:[],themselv:[8,16,17,36,37,41,42,50],thenc_1:[],theo:50,theoret:[],theori:[16,36,40,41,42,44,47],thepihut:[],therebi:[8,16,37],therefor:[16,39],thi:[0,2,4,5,6,8,9,10,11,12,13,14,15,16,17,26,27,28,29,30,31,35,37,38,39,40,41,42,43,44,45,46,48,49,50],thickest:[],thiel:50,thin:[],thing:[5,6,8,9,13,15,16,28,36,37,38,39,40,41,42,43,44,45,49,50],thing_subscribing_ao_cares_about:42,think:[12,16,26,36,37,38,39,41,42,43,44,45,46,48,50],thinner:[],thinnest:[],third:[16,38],thirti:[],this_dir:40,thoma:41,those:[8,16,35,39,41,49,50],thou:46,though:[8,12,16,36,39,41,42,45,46,49,50],thought:[16,17,36,38,42,50],thousand:[],thread:[0,1,4,5,7,8,10,16,30,35,36,37,38,39,40,41,44,46,49,50],thread_method_1:48,thread_method_2:48,thread_race_attr_1:48,thread_runner_fifo:0,thread_runner_lifo:0,thread_safe_attr_1:48,thread_safe_attr_2:[],thread_safe_attribut:48,thread_safe_attributes_2:48,thread_safe_attributes_3_unsaf:48,thread_safe_queu:[],thread_stopp:48,threadev:48,threadkil:48,threadsaf:[],threadsafeattribut:[30,48],threadsafeattributesinactiveobject:[],thredo:50,three:[16,36,38,39,40,41,42,45,46,49,50],three_puls:[11,42],threshold:38,throb:50,throe:8,through:[5,6,8,9,15,16,29,30,36,37,38,39,40,43,44,45,46,48,49,50],throughput:16,thrown:43,tick:[16,17],ticket:[],tie:[16,38,39,42,50],tied:[8,16,44],ties:[],tight:[36,50],tight_layout:[],tighten:44,tightli:[28,41,42,43,50],till:36,timat:8,time:[0,4,5,8,10,11,12,16,17,29,30,35,36,37,38,39,40,41,43,44,46,48,49],time_1:50,time_1_str:50,time_2:50,time_2_str:50,time_compress:[16,17],time_differ:50,time_in_sec:50,time_in_second:[16,17],time_keep:9,time_out:38,timeout:37,timeout_callback:37,timer:[37,40,50],times_in_inn:42,timeseri:[],timestamp:[29,42,43,46,50],timestamp_str:50,timezon:40,tini:[5,42,44,50],tip:46,tissu:[],titl:[5,9,39,44,50],to_b1:42,to_cod:[8,16,42,49],to_dai:40,to_method:[16,17,35,37,38,40,41,42,49],to_night:40,to_summ:40,to_tim:[16,17],to_weather_payload:40,to_wint:40,toast:[10,38,50],toast_tim:50,toast_time_in_sec:50,toaster:[10,38,41],toaster_142x5:[],toaster_:10,toaster_baking_to_toast_spec:[],toaster_off_to_baking_trace_spec:[],toaster_oven:41,toaster_oven_1:50,toaster_oven_2:50,toasteroven:[38,41,50],toasterovenmock:50,toasting_buzz_test_spec:50,toasting_entri:38,toasting_time_m:50,toateroven:[41,50],todai:16,togeth:[15,16,30,36,40,41,42,43,47,48,50],toggl:50,told:50,toler:[16,50],toleranc:50,tolern:50,tolernance_in_m:50,tome:36,tonsil:50,too:[0,8,9,15,16,36,37,38,39,40,41,42,43,44,49,50],too_cold:41,too_hot:41,took:[16,35,36,46,50],tool:[5,8,16,35,36,37,41,42,43,45,50],top:[0,7,8,9,10,15,16,17,29,31,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50],top_bound:50,topic:[16,45],topolog:[9,35,36,38,39,41,42,49,50],topology_a:9,topology_h:9,toronto:40,total:44,totalitarian:38,touch:[5,42,50],tough:48,toward:[9,16,38,50],tpath:9,trace:[0,4,8,15,16,24,28,29,31,35,38,39,40,41,46,48,50],trace_callback:[37,42],trace_l:37,trace_lin:50,trace_queue_nam:37,trace_result:37,trace_target:50,trace_through_all_st:50,trace_without_datetim:42,track:[16,17,37,38,41,42,43,46,50],tracker:[],trade:[38,39,41,42,49,50],tradit:[5,16,36,39,41,50],traffic:16,train:[16,36,42],trajectori:[],tran:[8,9,10,11,12,16,17,25,35,37,38,39,40,41,42,44,46,49,50],tranduc:38,trans_:9,trans_to_c2_s1:[],trans_to_c2_s2:[],trans_to_c2_s3:[],trans_to_fb11:35,trans_to_fb1:35,trans_to_fb:35,trans_to_fc1:[35,42,49],trans_to_fc2:[35,49],trans_to_fc:[35,42,49],trans_to_tc1:49,trans_to_tc2:49,trans_to_tc:49,transact:43,transduc:[8,16,38],transfer:[38,39,42,44],transform:[],transit:[0,4,8,9,11,12,16,17,31,35,39,40,41,43,44,46,49,50],transitori:50,translat:[36,38,43],transmit:[16,37,45],transpar:[],transpir:50,travel:[],travers:39,treat:[9,41,50],tremend:16,trend:36,trends_nrtr:[],tri:[8,16,36,38,42,48,49,50],trial:38,triangl:[],tribe:39,trick:16,tricki:41,trickl:42,trigger:[8,9,16,17,38,39,40,41,44,49,50],trigger_pul:39,trip:16,trivial:[16,35,41,42,50],troop:16,troubl:[5,16,39,41,49],troubleshoot:[4,36],troublesom:5,truck:38,truli:[16,41],trust:[16,42,50],truth:16,tube:[],tunabl:[38,50],tune:[16,38],tupl:[40,41,42],turbin:38,turn:[5,6,8,10,15,16,29,35,36,38,39,40,41,42,43,44,45,46,48,49,50],turn_off_sprinkl:40,turn_on_sprinkl:40,tutori:[33,36,37,45],twain:16,tweak:16,tweek:[],twice:[42,50],twist:36,two:[0,4,5,8,13,15,16,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],twodcellularautomatawithanglediscoveri:[],twodcellularautonomata:[],tx_routing_kei:16,type:[4,6,11,16,31,35,36,38,40,41,42,43,45,46,49,50],typic:[0,16,30,35,36,41,42,48,50],typof:[],u3uc:[16,37],ubuntu:[],ugli:50,ultim:[4,8,39,41,46,50],ultimate_hook_exampl:38,ultisnip:[41,50],uml:[5,8,15,16,35,36,37,38,40,42,43,44,50],umlel:[],umlet:[15,16,36,41,42,43],umletino:42,unawar:42,uncom:[28,42,43],uncomfort:50,undefin:[42,50],under:[5,16,36,41,42,45,50],underl:50,underli:[8,50],underneath:[],understand:[8,9,16,27,30,35,36,38,39,40,41,42,43,44,46,47,48,49,50],understood:36,underworld:50,unexcept:16,unexpect:[16,41,42],unfamiliar:44,unfold:16,unforeseen:16,unfortun:[5,36,41],ungodli:5,unhandl:[6,10,11,12,16,17,25,35,38,39,41,42,44,46,49,50],unhanld:[26,42,43],unifi:41,uniform:38,uniqu:[6,16,31,42,43,49,50],unison:[16,37,38],unit:[5,8,15,17,38,40,42,43,50],univers:[8,16,36,47,50],unives:[],unless:[8,16,42,50],unlik:[5,8,16,39,42,47,48],unlink:16,unload:39,unlock:[30,41,48],unmanag:8,unnecessari:[11,42],unneed:50,unorgan:16,unpredict:38,unprocess:42,unprotect:[5,16],unreason:[],unreli:[],unrespons:50,unseen:6,unstabl:46,unstart:[],unsupport:47,unsuspect:39,untest:50,until:[5,8,9,16,30,37,38,39,40,41,42,46,48,50],unus:50,unusu:16,unwind:[7,8,42,43],upcom:50,updat:[15,16,29,36,42,43,50],update_angl:[],upon:[5,8,13,16,17,26,34,35,38,39,40,41,42,43,46,49,50],upper:[16,41,50],upward:[],url:40,usag:50,use:[0,5,8,11,12,15,16,25,26,27,29,30,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50],used:[0,2,5,6,8,9,10,11,12,15,16,30,31,36,37,38,39,40,41,42,43,44,45,46,48,49,50],useful:[9,11,16,36,37,38,39,41,42,50],useless:50,uselessli:16,user:[0,8,37,38,39,41,42,43,45,46,50],uses:[0,4,6,8,16,36,38,39,40,41,45,48,49,50],using:[0,4,5,6,8,9,15,16,27,29,30,31,35,36,37,38,39,40,41,43,45,46,48,49,50],usual:50,utf:40,util:[15,42,43],uuid5:0,uuid:0,vagu:[],vain:5,valid:9,valour:16,valu:[6,8,16,26,30,38,42,43,48,50],valuabl:[],valv:40,vancouv:40,vantag:[16,50],variabl:[5,8,9,16,29,30,35,38,39,41,42,43,45,46,48,50],varient:[],varieti:37,variou:[8,16,39,42,46,50],veer:16,veloc:[],vendor:41,vent:42,venv:50,verbiag:[],verbos:[],veri:[0,5,15,16,27,30,31,35,36,38,39,40,41,42,43,44,46,48,49,50],verifi:[36,38,50],vers:43,version:[4,37,40,42,45,49,50],versu:50,vertic:[41,42,50],vestigi:50,via:[38,42,45],viabl:[],victim:39,victori:5,video:[16,42],videoid:[],view:[5,8,16,36,37,38,39,41,44,46,47,50],vigil:16,vim:[35,41,42,50],virtual:50,visibl:[40,41,42],visio:[36,43],vision:[16,35,36],visit:42,visual:[35,50],vital:41,vitamin:41,vnc:[],voic:16,voltag:[39,50],volum:36,voodoo:16,vortex:38,wai:[0,5,8,11,13,16,17,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],waist:5,wait:[0,5,10,11,16,17,30,36,37,38,39,40,41,42,44,46,48,50],waitcomplet:46,waiting_to_adv:[16,17],waiting_to_lur:[16,17],wake:[8,38,50],walk:[38,49,50],walker:50,wall_cl:[],wallleftblackrightblack:[],wallleftblackrightwhit:[],wallleftwhiterightblack:[],wallleftwhiterightwhit:[],want:[9,12,13,16,26,27,29,30,36,37,38,39,40,41,42,43,45,46,48,49,50],war:[5,16,17],warbot:16,ward:49,warhors:16,warn:42,wasn:[16,28,38,40,42,43,46,50],wast:[8,16,38,39,41,43,50],watch:[0,5,16,36,37,39,42,46,49,50],watch_external_weather_api:[],watch_external_weather_api_entri:[],watch_external_weather_api_weather_report:[],water:[16,17,40],water_time_sec:40,wave:[16,38,40,50],weak:16,weaken:16,weapon:[5,16,35],wear:16,weather:[36,40],weather_dict:40,weather_read:[],weather_report:[],weather_results_dict:40,weather_track:[],weather_work:40,weather_worker_city_detail:40,weather_worker_entry_sign:40,weather_worker_get_weath:40,weather_worker_weath:40,weatheropenapiresult:40,weatherreport:[],weav:16,web:[40,45,50],websit:[40,45],weekend:[],weigh:[5,42],weight:[5,35],weird:42,weirder:42,well:[0,5,6,9,16,36,39,41,42,44,45,49,50],went:[36,45],wenzel:45,were:[0,4,5,8,16,29,36,37,38,39,40,41,42,43,46,48,49,50],weren:[5,16,36,49,50],western:16,what:[5,8,9,14,16,27,28,29,31,35,36,37,38,39,41,44,45,46,47,48,49,50],whatev:[16,36,41,42,44,45,50],whatever_name_you_w:[],when:[4,5,8,9,11,13,15,16,17,27,28,29,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],whenev:38,wher:[],where:[0,5,8,9,13,16,24,30,35,37,38,39,40,41,42,45,46,48,50],wherea:43,wherev:50,whether:49,which:[0,5,6,8,9,13,15,16,26,27,28,29,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],whichev:[38,42],whine:39,whisper:50,white:[10,50],white_light_off:10,white_light_on:10,white_mask:[],who:[5,8,16,36,37,38,39,41,42,43,48,49,50],whoever:[],whole:[5,16,26,37,39,42,43,50],wholli:36,whose:[16,36],why:[15,16,30,35,36,38,40,41,42,43,46,47,48,50],wide:[],widget:41,width:[],wiki:38,wikipedia:50,wild:48,willing:16,wilt:[],win:5,wind:40,window:[16,24,37,50],wipe:[],wire:[16,37,40],withe:[],within:[0,4,5,6,8,9,12,16,17,25,35,36,37,38,39,41,42,43,44,46,48,49,50],without:[5,8,15,16,27,36,38,41,42,43,48,49,50],woke:46,wolfram:[],won:[5,11,13,36,38,39,41,42,43,50],wonder:38,word:[5,8,16,36,43,45,50],work2:42,work:[0,4,5,8,9,10,13,14,15,16,29,30,35,36,37,38,39,40,41,43,45,46,47,48,49,50],worker1:42,worker2:42,worker:[5,10,41],workflow:16,world:[5,8,13,16,36,38,41,42,45,46,50],worri:[39,41,42,46,49,50],wors:[5,16],worst:[16,50],worth:[16,36,38,41,49],worthwhil:50,would:[0,5,8,9,11,12,13,15,16,26,27,28,29,30,31,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50],wouldn:[16,36,39,40,41,42,44,49,50],wound:[16,17],wrap:[6,9,14,16,17,37,41,42,43,48,49,50],wrapper:9,wrestl:[45,49],write:[4,5,8,15,16,27,28,30,35,36,37,38,39,40,41,42,43,45,46,48,50],written:[4,5,8,9,16,35,36,37,38,39,41,42,45,48,49,50],wrong:[9,16,30,36,39,48,49],wrote:[5,16,36,37,38,39,40,44,45,49,50],wsl:50,wta_entri:[16,17],wta_exit:[16,17],wtl_entri:[16,17],wtl_exit:[16,17],wtl_second:[16,17],www:[],x15:50,x_px:41,xaxi:[],xml:8,xor:[],y_px:41,yaml:8,yaxi:[],year:[5,36],yell:[16,17,50],yellow:[],yes:[16,41,50],yet:[5,8,12,15,16,38,39,40,41,42,43,44,48,49,50],yield:38,yml:[8,45],you:[0,2,4,5,6,8,9,11,12,13,14,15,16,25,26,27,28,29,30,31,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50],your:[0,4,5,6,8,9,11,12,13,14,15,16,25,26,27,28,29,30,31,35,36,37,38,39,40,41,44,45,46,47,48,49,50],your_parent_state_method:42,your_signal_nam:42,your_state_method_nam:42,yourself:[8,16,38,39,41,42,47,49],youtub:42,z_px:41,z_pz:41,zap:39,zero:[5,16,18,33,36,38,40],zero_to_on:[7,18,19,20,21,22,23,41,50],zeromq:50,zip:[16,29,42,43,50],zoologi:5,zoom:42,zuvk:[]},titles:["Active Object","Architecture","Cellular Automata","City Sprinkler","Comprehensive","Concurrency: the Good Parts","Events","Examples","Glossary","Hsm","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","Mongol Horse Archer","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","Python Statecharts","Installation","Interacting Statecharts (Same Machine)","Introduction","Spy and Trace Across a Network","Patterns","Simple Posting Example","Quick Start","Diagrams","Recipes","Reflection","Hacking to Learn","Setting Up RabbitMQ","Active Object Example","Testing","Thread Safe Attributes","Using and Unwinding a Factory","Tutorial: Zero To One"],titleterms:{"abstract":[42,50],"catch":42,"class":[37,41,42,49],"final":41,"function":[37,42,44],"import":[37,41,44],Adding:42,And:42,For:16,Going:42,Has:42,One:[42,50],The:[16,37,41,43],Using:[42,43,49],abil:37,about:[36,41,42],across:37,activ:[0,42,46],activeobject:42,activeojbect:[],add:[37,42,44],analog:[],anoth:42,ansibl:45,answer:44,anyth:44,approach:49,archer:16,architectur:1,around:40,arrow:41,attach:[16,41,42],attribut:[42,48],augment:[],augmentng:42,automata:2,balkan:[],basic:[45,50],behavior:[42,43],better:44,between:42,boiler:[37,42],build:[16,42],callback:[37,49],can:37,cancel:42,canva:[],capabilit:[],capabl:42,cellular:2,challeng:44,chart:43,citi:3,citydetail:[],cityweath:40,close:37,code:[37,42,44,50],colloqui:[],colour:41,common:44,commun:42,compon:38,comprehens:[4,42],concurr:5,condit:42,connect:37,construct:41,consum:37,content:42,context:[16,36,37,41],count:37,creat:[37,42,49],current:42,deceit:16,decrypt:37,deep:41,defer:[38,42],demonstr:42,describ:42,descript:43,design:[16,37,43,50],destroi:42,detail:[16,41,43],determin:42,diagram:[41,42],docstr:37,document:36,doe:[],dot:41,draw:[37,41,42],dynam:[],els:41,embed:[],enter:[],entri:42,entropi:[],escal:[],event:[6,37,38,41,42,44,49,50],exampl:[7,16,35,37,39,46,49,50],exit:42,experienc:[],explain:43,extend:41,extern:42,extrem:43,fabric:0,factori:[42,49],fall:41,feder:41,feedback:42,fifo:42,figur:40,first:[16,44],flat:42,foreignhsm:37,frame:44,from:[42,43],game:[],gener:[],get:37,glossari:8,good:5,guard:[42,44],hack:44,handl:42,handler:42,hardwar:50,have:[37,42,43],heartbeat:42,hiearchi:44,high:[41,43],highlevel:[],highlight:[],hint:[],histor:16,histori:[36,38,41,50],hook:[38,42,50],hors:16,horseman:16,how:43,hsm:[9,37,42],hypothesi:44,icon:41,idea:[],indic:33,inform:[37,40,42],inherit:41,init:44,initi:42,insid:42,instal:[34,41,45],instrument:[4,42],interact:35,intern:44,introduct:36,invent:42,iter:50,its:[16,37],learn:[44,45],level:[41,43],librari:37,lifo:42,link:37,linux:45,live:[42,43],live_spi:42,log:37,logger:42,machin:[35,42],make:[37,42,44],mechan:[],medium:41,mesh:16,messag:[37,45],method:[42,49],mind:16,minim:42,miro:[41,42],mistak:44,model:16,modul:6,mongol:16,more:42,most:41,multi:[42,50],multichart:38,multipl:42,multishot:42,name:42,need:[],network:[16,37,40,45],newbi:[],noth:[],number:[],object:[0,37,42,46],off:37,one:[42,50],onedcellularautomata:[],openweathermapcitydetail:40,organ:[],orthogon:38,other:[42,43,44],our:[16,37,44],out:40,output:[37,43],oven:50,over:[],overload:42,overview:16,own:42,pai:[],parent:42,part:5,partial:44,pass:[40,42],pattern:[38,45],payload:[41,42,50],pend:38,phenomenon:[],pictur:44,plate:[37,42],point:[41,42],post:[39,42],processor:41,produc:37,program:37,proof:50,provid:[],pub:41,publish:[41,42],python:[33,42],question:[44,50],quick:40,rabbitmq:[37,45],race:38,random:[],react:37,recal:42,recip:42,refactor:[],reflect:43,regist:49,releas:42,remind:38,requir:[37,44],returnstatussourc:6,ride:[],rule30:[],rule:41,run:44,safe:[42,48],same:35,scott:[],scribbl:42,see:[42,44],self:[],send:37,sequenc:[41,42],set:[37,45],setup:50,share:[],shot:[42,50],shutdown:37,signal:[6,42,43],signalsourc:6,simpl:[35,39,50],sketch:[],small:[],softwar:41,some:[16,37],someth:[],sourc:42,specif:[37,42,49,50],sprinkler:[3,40],spy:[37,42,43],standard:49,start:[40,42],state:[41,42,43,44,49],statechart:[33,35,37,41,42,49],statemachin:[],stop:42,stori:50,structur:41,sub:41,subclass:42,subscrib:[41,42],subscript:[],subsect:[],subsubsection_titl:[],summari:49,system:42,tabl:33,tactic:16,target:42,technic:16,templat:49,termin:41,test:[42,43,47,50],than:42,thi:36,thought:43,thread:[42,48],through:[41,42],time:[42,50],titl:[],toaster:50,trace:[37,42,43],transit:[38,42],translat:50,turn:37,tutori:50,twodcellularautomata:[],ultim:38,uml:41,umlet:[],unit:16,unwind:49,use:42,using:42,viabl:42,view:43,visual:[],volk:[],wall:[],warn:41,what:[40,42,43],when:[],why:49,window:45,work:[42,44],worker:42,write:49,you:42,your:[42,43],zero:50}})
\ No newline at end of file
+Search.setIndex({docnames:["activeobject","architecture","cellular_automata","city_sprinkler","comprehensive","concurrency_essay","event","examples","glossary","hsm","i_bitcoin_miner_toaster_oven","i_create_a_multishot","i_create_a_one_shot","i_defer_and_recall","i_determining_the_current_state","i_making_sequence_diagrams_from_trace","i_mongol_example","i_mongol_with_empathy_code_listing","i_navigation_1","i_navigation_2","i_navigation_3","i_navigation_4","i_navigation_5","i_navigation_6","i_networking_instrumentation_file_table","i_scribble_on_the_spy","i_seeing_your_signals","i_spy_reactive","i_test_with_spy","i_test_with_trace","i_thread_safe_attributes","i_trace_reactive","i_uml_trend","index","installation","interactingcharts","introduction","networked_instrumentation","patterns","postingexample","quickstart","reading_diagrams","recipes","reflection","scribbleexample","setting_up_rabbit_mq","singlechartexample","testing","thread_safe_attributes","towardsthefactoryexample","zero_to_one"],envversion:{"sphinx.domains.c":1,"sphinx.domains.changeset":1,"sphinx.domains.cpp":1,"sphinx.domains.javascript":1,"sphinx.domains.math":2,"sphinx.domains.python":1,"sphinx.domains.rst":1,"sphinx.domains.std":1,sphinx:55},filenames:["activeobject.rst","architecture.rst","cellular_automata.rst","city_sprinkler.rst","comprehensive.rst","concurrency_essay.rst","event.rst","examples.rst","glossary.rst","hsm.rst","i_bitcoin_miner_toaster_oven.rst","i_create_a_multishot.rst","i_create_a_one_shot.rst","i_defer_and_recall.rst","i_determining_the_current_state.rst","i_making_sequence_diagrams_from_trace.rst","i_mongol_example.rst","i_mongol_with_empathy_code_listing.rst","i_navigation_1.rst","i_navigation_2.rst","i_navigation_3.rst","i_navigation_4.rst","i_navigation_5.rst","i_navigation_6.rst","i_networking_instrumentation_file_table.rst","i_scribble_on_the_spy.rst","i_seeing_your_signals.rst","i_spy_reactive.rst","i_test_with_spy.rst","i_test_with_trace.rst","i_thread_safe_attributes.rst","i_trace_reactive.rst","i_uml_trend.rst","index.rst","installation.rst","interactingcharts.rst","introduction.rst","networked_instrumentation.rst","patterns.rst","postingexample.rst","quickstart.rst","reading_diagrams.rst","recipes.rst","reflection.rst","scribbleexample.rst","setting_up_rabbit_mq.rst","singlechartexample.rst","testing.rst","thread_safe_attributes.rst","towardsthefactoryexample.rst","zero_to_one.rst"],objects:{"":{activeobject:[0,0,0,"-"],event:[6,0,0,"-"],hsm:[9,0,0,"-"]},"activeobject.ActiveFabricSource":{clear:[0,3,1,""],publish:[0,3,1,""],start:[0,3,1,""],stop:[0,3,1,""],subscribe:[0,3,1,""],thread_runner_fifo:[0,3,1,""],thread_runner_lifo:[0,3,1,""]},"activeobject.ActiveObject":{append_publish_to_spy:[0,3,1,""],append_subscribe_to_spy:[0,3,1,""],cancel_event:[0,3,1,""],cancel_events:[0,3,1,""],make_unique_name_based_on_start_at_function:[0,3,1,""],run_event:[0,3,1,""],start_thread_if_not_running:[0,3,1,""],stop:[0,3,1,""],trace:[0,3,1,""]},"event.Event":{dumps:[6,4,1,""],has_payload:[6,3,1,""],loads:[6,4,1,""]},"event.SignalSource":{name_for_signal:[6,3,1,""]},"hsm.HsmEventProcessor":{augment:[9,3,1,""],child_state:[9,3,1,""],dispatch:[9,3,1,""],init:[9,3,1,""],is_in:[9,3,1,""],start_at:[9,3,1,""],top:[9,3,1,""],trans:[9,3,1,""],trans_:[9,3,1,""]},activeobject:{ActiveFabric:[0,1,1,""],ActiveFabricSource:[0,2,1,""],ActiveObject:[0,2,1,""]},event:{Event:[6,2,1,""],OrderedDictWithParams:[6,2,1,""],ReturnStatusSource:[6,2,1,""],Signal:[6,1,1,""],SignalSource:[6,2,1,""]},hsm:{HsmEventProcessor:[9,2,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","attribute","Python attribute"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","staticmethod","Python static method"]},objtypes:{"0":"py:module","1":"py:attribute","2":"py:class","3":"py:method","4":"py:staticmethod"},terms:{"04d":40,"0bmhjf0rke8":[],"100m":[38,50],"13th":16,"142x5zhqemk5lljxgzeitbwpv2oxqpfahj":10,"1845_rc03":[],"1980s":[],"1990s":[36,41],"1st":[46,50],"2000s":36,"2005_2006":[],"257m":5,"2nd":[40,41,46,50],"2onedcellularautomata":[],"2twodcellularautomata":[],"33691e":[],"37474f":[],"3nd":46,"3rd":37,"3th":46,"4nd":46,"4th":46,"70s":5,"75c8c":[15,31,39,42,43],"8ahweo_dgs0":[],"90s":36,"95a8c":[15,42,43],"abstract":[16,38,41,49],"break":[5,15,16,30,38,39,40,41,42,43,46,48,49,50],"case":[12,16,39,40,41,42,46,50],"catch":[8,10,16,17,35,37,38,40,41,49,50],"class":[0,6,7,8,9,10,14,16,17,18,19,20,21,22,23,26,30,36,38,39,40,43,44,47,48,50],"default":[0,16,38,42,45,50],"enum":6,"final":[8,9,16,36,37,38,39,46,50],"float":[5,50],"function":[0,4,6,8,9,11,14,35,36,38,39,41,43,48,49,50],"import":[5,10,12,16,17,26,27,28,29,35,38,39,40,42,43,46,48,49,50],"int":[26,42,43,50],"long":[16,35,38,39,40,42,50],"new":[0,5,6,8,9,16,27,28,29,36,37,38,39,40,41,42,43,44,45,46,49,50],"public":[36,40,45,46],"return":[0,6,8,9,10,11,12,16,17,25,35,36,37,38,39,40,41,42,44,46,49,50],"short":[16,38,41,44,50],"static":[6,16,37,39,41,42],"super":[5,9,10,11,12,16,17,25,36,37,38,39,40,41,42,44,46,49,50],"switch":[4,30,38,48,50],"throw":[15,16,42,43,50],"true":[0,6,8,9,10,11,12,16,17,37,38,39,40,41,42,43,44,46,50],"try":[5,9,16,30,36,37,38,39,40,41,42,44,46,48,49,50],"typeof":[],"var":[],"while":[4,5,8,11,15,16,17,30,36,37,38,39,40,41,42,43,45,46,48,49,50],Adding:37,And:[16,17,41,50],Are:50,Being:50,But:[16,30,36,37,38,39,40,41,42,43,44,45,48,49,50],Eve:50,For:[0,6,8,28,37,38,40,41,42,43,46,48,49,50],GPS:40,Going:[],His:[5,16,36,50],Its:40,NOT:[0,42,45,46],Not:[8,50],One:[8,16,33,39,44,48],Such:[16,41,50],THE:[],That:[5,16,29,35,38,39,42,43,44,49,50],The:[0,2,4,5,6,8,9,10,11,12,15,17,26,27,29,30,31,35,36,38,39,40,42,44,45,46,47,48,49,50],Their:[5,9,16,49],Then:[5,9,15,16,35,36,38,39,40,41,42,43,44,46,49,50],There:[0,5,8,9,13,16,31,35,36,37,38,39,40,41,42,43,44,45,50],These:[5,9,16,30,36,38,41,45,48,49,50],Use:[5,37,38,50],Used:9,Useful:9,Uses:42,Using:[7,16,36],WLS:[],With:[16,29,39,41,42,43,49,50],Yes:[42,50],__add__:[16,17],__getattr__:[26,42,43],__init__:[6,10,16,17,37,38,40,41,42,48,50],__main__:[10,16,37,40,41,42,44,50],__name__:[10,16,37,40,41,42,44,49,50],__post_ev:0,_attribut:[42,48],_blank:[],_decrypt:37,_dict:40,_encrypt:37,_fake_new:38,_fake_news_gener:38,_gener:[],_id:40,_imag:[],_lock:48,_recip:[],_rlock:48,_static:40,_strip_trac:37,_time_in_inn:[],_times_in_inn:[],_valu:48,a01:42,a02:42,a11:41,a1_entri:42,a1_to_b1:42,a53:50,aa00ff:[],abandon:[41,42],abil:[8,16,36,39,50],abl:[8,16,37,38,41,43,50],about:[0,5,8,9,11,12,15,16,27,28,31,37,38,39,40,43,44,45,46,48,49,50],abov:[4,9,15,16,29,37,38,39,40,41,42,43,44,45,46,48,49,50],abs:[],absenc:[],absent:[],absolut:[16,42,48],absorb:[],academ:[],acceler:8,acceleromet:[],acceller:[],accept:[30,37,42,47,48],accerer:[],access:[5,8,16,26,27,30,36,37,38,40,41,42,43,48,50],accid:42,accident:[16,41,49,50],accomod:50,accord:[8,16,41],account:[5,10,39,40,50],accumul:[41,50],accur:16,achiev:[5,16,40],acquisit:38,acronym:50,across:[6,9,16,26,30,36,38,39,41,42,43,45,48,49,50],act:[5,9,13,15,16,17,36,37,38,39,40,41,42,43,48,50],action:[0,8,9,16,36,39,41,42,44,46,49,50],activ:[1,4,5,8,11,15,16,25,27,28,29,30,31,35,36,37,38,39,40,41,43,44,48,49,50],active_object:[49,50],active_object_input_queu:0,activefab:[],activefabr:[0,42,46],activefabricsourc:0,activefactori:41,activefrab:[],activeobect:[42,50],activeobject:[0,10,16,38,39,40,41,43,44,46,49,50],activeobjectinstrumenttolog:42,activeoobject:[],actor:[41,50],actual:[5,8,9,15,16,17,28,31,35,36,38,41,42,43,44,46,48,49,50],adapt:38,add:[5,6,8,9,12,16,25,30,35,38,39,40,41,45,46,48,50],add_member_if_need:16,add_timeout:37,added:[6,16,36,37,39,40,42,48,49,50],adding:[8,16,38,50],addit:[4,8,16,37,42,43,48,50],address:[16,17,37,45,50],adher:[8,16,41],adjac:[9,36],adjust:[4,15,16,17,36,37,38,39,42,43,44],admistr:8,advanc:[9,16,17,36,41,48],advance_close_enough_for_circl:[16,17],advance_entri:[16,17],advance_exit:[16,17],advance_other_advanced_war_cri:[16,17],advance_senior_advanced_war_cri:[16,17],advance_war_cri:[16,17],advantag:16,adventur:50,advertis:50,advic:50,advis:50,advoc:[],aesthet:50,af_inet:37,affair:16,affect:[],afford:[],after:[4,5,8,16,27,28,36,38,39,40,41,42,43,44,45,46,48,49,50],afternoon:[],again:[0,9,16,35,38,39,40,42,44,46,49,50],against:[8,16,26,29,37,39,42,43,44,48,50],agent:16,aggreg:[24,37,38,41],aggress:38,aggression_max:38,agil:[],ago:[],agre:38,agress:38,ahead:[11,42],aim:[9,16],ain:16,air:5,aircraft:5,airforc:[],alan:[36,40,42],alarm:9,albert:41,alcohol:50,aleph2c:[40,41],alert:[],alexand:[8,38],algebra:16,algorithm:[8,9,36,38,39,42,44,49,50],align:[],aliv:[16,41],all:[0,4,5,6,8,9,11,15,16,17,24,27,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],all_readi:38,alli:[],allow:[4,8,16,37,38,39,40,45,46,50],allowfullscreen:[],allur:16,almost:[16,39,41,47,48,49,50],alon:[16,42,50],along:50,alpha:[],alreadi:[5,9,16,17,36,38,40,41,42,45,46,50],also:[4,5,6,8,9,11,15,16,30,36,37,38,39,40,41,42,43,44,45,48,49,50],altan:[16,17],altan_192:16,alter:16,alwai:[5,8,9,16,38,39,41,42,45,50],alzheim:[],ambiti:[38,43],american:5,ammunit:[16,17],ammunition_low:[16,17],amoungst:[],amount:[5,16,27,38,41,42,43,50],ampl:[],amplifi:[39,43],analog:[41,44],analysi:[],analyz:[],ancestor:[9,16,50],ancestr:16,anchor:8,angl:8,angle_in_radian:[],angri:16,ani:[0,4,5,6,8,9,12,16,26,37,38,39,40,41,42,43,44,46,47,48,50],anim:36,annihil:50,annoi:50,announc:50,anoth:[4,5,6,8,9,15,16,17,30,31,35,36,37,38,39,40,41,43,44,45,46,48,49,50],answer:[5,16,30,36,40,41,47,48,49,50],anthropologist:36,anti:[41,42,50],antiqu:[],anymor:[16,39,42,50],anyon:[16,36,39,43,48,50],anyth:[5,39,40,41,42,43,49,50],anytim:[8,16,30,37,38,42,46,50],anywai:[41,50],anywher:[16,41,50],ao1:[42,43],ao2:42,aos:[11,39,42],apart:[5,38,50],api:[0,11,12,16,25,36,37,40,41,42,46,49,50],api_hold_off_time_in_sec:40,api_kei:40,api_l:40,api_live_entry_sign:40,api_live_fresh_api_cal:40,api_live_init_sign:40,api_live_network_error:40,api_lookup_data:40,api_lookup_data_city_detail:40,api_lookup_data_entry_sign:40,api_lookup_data_init_sign:40,api_lookup_data_request_city_detail:40,api_paus:40,api_paused_entri:40,api_paused_get_weath:40,api_query_url:40,api_weather_dict:40,apologet:[],app:[45,50],appear:[16,42,50],append:[0,6,9,16,17,37,41,48],append_publish_to_spi:0,append_subscribe_to_spi:0,append_to_spi:37,append_to_trac:37,appendix:50,appid:40,appli:[8,16,36,42,46,48,50],applic:[5,16,36,41,42,49,50],approach:[0,5,8,9,16,36,38,42,44,50],appropri:[],approxim:[],apt:45,arab:5,arbitrari:[16,42,48],arcan:41,archan:[],archer:[7,17],architect:[8,38],architectur:[16,33,38,39,42,50],area:[5,38,41],aren:[5,8,16,38,39,41,42,50],arg:[6,9,40,41,42,48,50],argu:16,arguement:41,arguemnt:[],argument:[8,9,11,37,39,41,42,46,49,50],aris:[16,38,50],arm:[15,16,28,29,31,38,39,42,43,50],armi:16,armin:8,armli:[],armour:16,around:[5,8,16,29,37,38,42,43,48,50],arrai:[9,38,50],arrang:50,array_equ:[],arriv:[16,50],arrow:[8,9,16,17,37,38,39,40,42,44,46,50],art:[37,42,46],articl:36,artifact:[42,50],artifici:[8,13,38,42],ascend:50,ascii:[8,15,37,42,43,50],asctim:42,asid:[],ask:[5,16,36,37,38,39,40,41,42,44,46,47,49,50],aspect:[36,38,41,42,50],assert:[0,6,9,16,28,29,38,41,42,43,50],assign:[0,9,42,48,49,50],assimil:[],assist:[15,42,43],associ:[0,39,42,44,50],assort:[],assum:[16,27,38,40,41,42,43,44,49],assumpt:[36,38],asychron:[],asycio:36,asymetr:50,asymmetr:36,asynchron:[5,8,36,41,42],asyncio:50,at15:50,atan:[],ativeobject:[],atom:[30,42,44,48],attach:[40,46,50],attachment_point_1:41,attachment_point_2:41,attack:[16,17,44],attempt:36,attent:[4,5,9,15,16,35,38,39,41,42,43,46,49,50],attractor:16,attribut:[1,6,7,9,10,16,30,37,38,39,40,41,46,50],attribute_1:41,attribute_2:41,attributut:[],audienc:[41,50],augment:[9,11,38,39,41,42,50],augustin:5,aureliu:[],australia:[],author:[36,38],authorized_kei:45,authorizing_author:38,authorizing_entri:38,autist:16,auto:[42,49],autocorrel:[],autodoc:[],autom:45,automat:[16,38,40,41,42,45,48,49,50],automata:7,autonom:16,autonoma:[],autoplai:[],avail:[5,36,41,42,50],avalanch:16,avion:[5,36],avoid:[5,11,16,30,39,40,41,42,43,44,48,49,50],awai:[15,16,17,36,38,39,40,41,42,43,46,50],await:[27,42,43],awaken:50,awar:[5,16,41,42,50],awesom:[],awkward:[8,44],axi:[41,50],b11:42,b11_entri:42,b11_inner_most:42,b11_other_inner_most:42,b1_entri:42,b1_exit:42,b1_init:42,b27300:[],b35975e18dc93725acb092f7272cc6b8:40,b_chart:35,baba:32,babi:5,back:[2,3,4,8,9,16,30,35,36,37,38,39,40,41,42,44,46,48,49,50],background:[16,35,36,38,42,46,50],backward:[9,41],bad:[5,16,35,37,38,42,50],baffl:48,bafflingli:16,bait:16,bak:47,bake:[10,38,42,50],bake_press:41,bake_tim:50,bake_time_in_sec:50,baking_buzz_test_spec:50,baking_entri:38,baking_st:[],baking_time_m:50,balanc:5,ball:42,balloon:50,ban:50,bang:16,bank:38,bankruptci:[],bar:[41,50],barg:[0,8,11,42,50],barometr:40,barrag:16,barrier:[],bartend:50,base:[0,8,9,16,30,37,38,40,42,43,44,46,50],base_state_method:49,basic:[6,16,26,36,38,42,43,46],basic_consum:37,basic_publish:37,basicconfig:42,bate:16,batteri:[15,39,42,43],battery_charg:[28,29,31,39,42,43],battl:[5,16,17],battle_entri:[16,17],battle_init:[16,17],battlefield:16,battleground:5,bb_handler:35,beagleboard:50,beat:[5,11,40,42],beauti:[41,43,49],beautifulli:9,beazlei:50,becam:[5,36,41,42],becaus:[5,6,8,13,16,28,30,35,36,37,38,39,40,41,42,43,44,46,48,49,50],becom:[5,8,15,16,29,36,39,40,41,42,43,49,50],been:[0,2,4,5,6,8,9,16,28,30,34,35,36,37,38,39,40,41,42,43,44,46,48,49,50],befor:[0,5,6,8,9,10,12,16,30,36,37,38,39,40,41,42,44,45,46,48,49,50],began:[39,50],begin:[0,5,8,9,15,16,17,35,37,38,39,41,42,43,44,46,48,50],beginn:[5,48],behalf:41,behav:[4,12,15,16,17,36,38,39,40,42,43,46,48,49,50],behavior:[8,16,25,27,28,29,35,37,38,39,40,41,44,46,49,50],behavior_nam:38,behaviour:[16,36,37,50],behind:[36,49,50],being:[5,6,8,9,11,13,16,17,24,26,29,30,37,38,39,41,42,43,46,48,49,50],beings:50,belabor:42,belief:16,believ:50,belong:[16,38,50],below:[16,26,35,40,42,43,45],benefici:41,benefit:[41,42,49,50],benifit:[],bernhard:45,besid:[8,40,41,42,50],best:[0,5,8,16,41,48,50],better:[5,16,36,38,40,41,42,46,48,50],between:[5,8,9,11,12,16,17,27,30,31,36,38,39,40,41,43,44,46,48,49,50],beyond:[9,16,41,50],bia:[],bias:16,big:[8,16,37,38,39,40,41,42,44,46,50],bigger:[4,5,39,43],billion:5,bin:50,binari:8,bind:[37,47],binocular:50,biolog:36,biologi:36,bird:50,bit:[5,10,12,16,35,37,39,42,44,46,49,50],bitcoin:10,bitcoin_address:10,bitcoin_miner_off:10,bitcoin_miner_on:10,black:[8,16,39,40,41,42,44,46,50],black_mask:[],blast:16,blazingli:50,blind:[16,28,35,42,43],blissfulli:42,blit:[],blob:[],block:[5,16,30,36,38,40,41,42,44,46,48,49,50],blocking_:[],blockingconnect:37,blog:[45,50],blue:[8,42,50],blueprint:[16,41],blur:16,bluster:16,board:50,bob:[37,45],bodi:[16,37],bog:16,boiler:[41,50],boilerpl:37,bold:38,bomb:5,bombard:16,book:[5,9,36,38,39,41,44],bool:[9,41],boot:[],bordercolor:[],borg:[],boss:50,bot:[16,45],both:[0,5,8,16,30,35,37,38,40,41,42,46,48,50],bother:[15,42,43,50],botnet:16,bottl:16,bottom:[5,40,48,49,50],bottom_bound:50,bounc:50,bouncer:50,bound:16,boundari:[8,41,42,44,50],bow:[16,17],box:[37,50],boyd:36,bracket:[31,38,42,43,44],brain:[],brake:[38,42],brand:[41,42,50],brass:[],brave:16,breach:8,bread:[39,50],breakpoint:[],brethren:16,brew:[],bridg:[],briefest:49,briefli:50,bring:[5,16,42,44],broad:16,broadcast:[15,42,43],broadcast_spi:37,broadcast_trac:37,broader:41,broken:[5,16,36,37,38,40,41,42,50],broker:45,brother:16,brown:[],browser:50,brush:[],bubbl:[38,41,42,50],buffer:[8,27,38,39,40,42,43],bug:[16,30,39,40,42,48,49,50],bui:[5,43,50],build:[4,5,8,9,13,17,35,36,37,38,39,40,41,43,44,46,49,50],build_data_structur:40,build_data_structure_entry_sign:40,build_data_structure_init_sign:40,build_data_structure_read_fil:40,build_next_mask:[],build_piston:38,built:[4,8,16,31,35,36,37,38,40,41,42,43,44,50],bulbu:41,bulk:40,bullet:50,bunch:[8,16,40,50],burden:50,buri:[],burn:[],burnabi:40,burst:[16,38],burst_ev:38,bus:50,buse:36,busi:[5,8,35,36,37,38,41,50],busy_count:38,busy_entri:38,busy_time_out:38,busy_time_out_hook:38,butterfli:[],button:[36,50],buttress:50,buzz:[44,50],buzz_tim:50,buzz_time_m:50,buzzer:50,buzzspec:50,c11:42,c1_a:37,c2_a:37,c_1:41,c_1_inner_st:41,c_1_outer_st:41,c_2:41,c_2_inner_st:41,c_2_outer_st:41,c_2_outer_state_entry_sign:41,c_2_outer_state_init_sign:41,c_2_outer_state_reset:41,c_chart:35,c_trace_consum:[24,37],c_trace_produc:[24,37],cach:40,cached_payload:40,cachefilechart:41,caf_second:[16,17],calcium:[],calcul:[30,48],calculu:16,call:[0,4,5,8,9,11,12,13,16,26,27,30,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],call_something_lat:50,callback:[8,16,17,35,38,42,50],callback_method:37,caller:[8,38],calori:[],came:[5,8,12,16,27,38,40,42,43,50],camera:16,camil:46,camp:36,campaign:50,can:[0,2,4,5,6,7,8,9,10,11,12,13,15,16,17,25,26,27,28,29,30,31,35,36,38,39,40,41,42,43,44,45,46,47,48,49,50],canada:[],cancel:[0,11,12,39,40,50],cancel_ev:[0,11,12,16,17,39,40,42,50],cancel_sourc:42,cannot:[36,38],canva:41,capabili:[],capabilit:[],capabl:[37,41],capacitor:39,capacitor_charg:[28,39,42,43],captur:[11,12,16,36,38,41,42],card:16,care:[0,8,12,15,16,41,42,43,44,46,49,50],career:5,carefulli:[28,42,43,50],cargo:5,carpet:50,carri:[8,16,40,41,50],cascad:39,cast:50,casual:41,cat:[42,45],catagor:8,categori:[],caught:[8,16,38,41,42,50],caus:[4,5,16,31,35,38,39,40,41,42,43,46,48,49,50],causal:[],ccceler:[],celciu:[],cell:36,cells_per_gener:42,cellular:7,celsiu:[38,40],cement:[],center:46,centr:38,centric:36,centuri:16,ceo:5,certain:[16,49,50],certainli:16,ceullular:[],chain:[16,42],challeng:[36,50],chamber:38,chanc:[16,17,40,41,42,48,50],chang:[4,5,9,12,15,16,29,30,36,37,38,40,41,42,43,45,46,48,49,50],changebordercolor:[],channel:37,chao:[16,38],chaotic:16,chapter:[36,38],charact:[0,31,37,42,43,50],characterist:[9,16,38,50],charg:[15,16,17,39,42,43],charli:50,chart1:[41,42],chart2:[41,42],chart3:42,chart:[0,4,7,8,9,11,12,13,14,15,16,17,25,26,27,31,35,37,38,39,40,41,42,44,46,49,50],chart_2_start:41,chart_attribute_1:41,chart_attribute_2:41,chart_b:35,chart_nam:37,chase:16,cheap:[43,50],check:[0,16,40,50],chemic:36,chicken:[16,17],child:[8,9,38,41,42,46],child_stat:9,child_state_graph_e1_s5:9,children:16,china:36,chines:[],chip:[],choa:[],choic:50,chomski:45,choos:[16,40,50],choppi:[],chortl:5,chose:42,christoph:[8,38],chunk:[5,46],cira:[],circa:36,circl:[8,16,17,41,50],circle_and_fir:[16,17],circuit:[16,38,39],circul:36,circular:50,circumst:36,citat:36,citi:40,city_detail:40,city_details_payload:40,city_id:40,city_to_id_json:40,city_weath:40,citydetail:[],citydetailspayload:40,cityweath:[],claim:[38,50],clariti:6,class1usedtosolveproblem:41,class2usedtosolveproblem:41,class_with_embedded_chart:[],classwithembeddedchart:41,classwithstatechartinit:42,claus:[8,38,41,42,50],clean:[6,49,50],clear:[0,9,16,29,30,40,42,43,46,48,50],clear_spi:[37,44,46,50],clear_trac:[16,37,42,46,50],clearer:[44,49,50],click:[4,8,16,38,41,50],client:[8,16,38,40,48],client_dequ:0,climb:[9,38,42,46,50],clip:50,clobber:9,clock:[30,36,38,48,50],clone:41,close:[10,16,17,38,39,41,50],close_enough_for_circl:[16,17],closer:16,closest:16,closur:37,cloud:40,club:38,clue:50,clumsi:37,cluster:[],clutter:[37,38,41,42,50],cmap:[],cod:40,code:[0,2,4,5,6,8,9,10,13,15,16,17,18,19,20,21,22,23,24,27,29,30,35,36,38,39,40,41,43,45,46,48,49],codebas:[40,48],cognit:[16,36,39,44,49],cohes:16,collabor:[16,38],collect:[5,6,8,9,16,36,37,40,41,42,45,50],collegu:35,collis:44,colon:36,color:[],color_numb:[],colour:37,column:[],com:41,combin:[],come:[4,5,8,15,16,36,37,38,39,40,41,42,43,45,46,50],comfort:[16,36,37],command:[5,16,17,28,38,42,43,45],comment:[9,15,16,28,38,39,42,43,49,50],commerci:42,committe:41,commmon:8,common:[8,9,30,38,41,42,47,48,49,50],common_behavior:[40,42],common_behaviors_entri:42,common_behaviors_entry_sign:40,common_behaviors_heart_beat:40,common_behaviors_hook_1:42,common_behaviors_hook_2:42,common_behaviors_init:42,common_behaviors_other_inner_most:42,common_behaviors_reset:42,common_behaviors_to_summ:40,common_behaviors_weath:40,common_featur:50,commonplac:[],commun:[0,5,8,16,35,36,38,40,41,47,49,50],comp:38,compact:[16,36,40,41,42,43,49],compani:[36,41,45,50],companion:50,compar:[5,16,26,28,29,37,38,40,41,42,43,46,50],comparison:[5,50],comparisonitem:[],compel:[],compens:5,compet:36,compil:[36,48,50],complet:[5,8,9,16,37,38,39,41,42,46,47,49,50],complete_circuit:16,complex:[5,8,16,35,36,38,41,42,43,46,48,49,50],complianc:16,compliant:[15,42,43,50],complic:[5,16,36,38,40,41,42,43,49,50],complicit:16,compon:[4,16,36,41,50],composit:[38,41,44],compound:41,comprehend:16,comprehens:[7,36],comprehensive_no_instrument:4,compress:[16,17,38,40],compromis:16,comput:[8,16,24,36,37,38,41,42,45,50],concaten:45,conceiv:[],concentr:16,concept:[8,16,36,50],conceptu:36,concern:[16,38,42,49],concert:42,concis:[35,36,49],conclud:16,conclus:16,concret:[],concurr:[30,35,36,41,42,48,50],condit:[4,5,8,16,17,30,38,39,40,41,44,48,50],conduct:[16,40],conduct_queri:40,conduct_query_entry_sign:40,conduct_query_readi:40,cone:[],conf:45,confid:[16,50],config:45,configur:[8,9,15,42,43,44,45],confin:[36,38],confirm:[16,38,44,45,50],conflict:5,confus:[16,36,41,50],connect:[8,16,35,38,40,41,42,45,46,50],connection_attempt:16,connectionparamet:37,consciou:50,consequ:16,conserv:47,consid:[5,8,9,15,16,29,38,42,43,44,50],consider:[36,40],consist:[16,37,38,40,41,50],conspir:50,conspiraci:50,constant:16,constraint:36,construct:[6,8,9,12,14,16,30,36,37,38,39,40,42,43,45,48,50],constructor:42,consult:45,consum:[8,16,24,36,40,41,42],consumpt:[16,50],contact:40,contain:[4,5,6,8,16,27,29,31,35,36,37,38,39,40,41,42,43,44,46,49,50],contemporari:50,contemptu:16,content:[1,4,16,33,39,40,41,48,50],context:[5,8,29,38,42,43,44,48,49,50],contextu:41,contin:[],continu:[5,8,16,36,38,39,41,42,46,50],contract:38,contractor:5,contradict:[36,42],contrari:44,contrast:[8,38],contribut:[8,36,41],contriv:40,control:[4,12,16,30,38,39,40,41,42,43,44,45,46,48,49,50],conu:[],conundrum:[16,36],conveni:38,convent:[16,50],convers:[41,43],converst:[],convert:[8,16,36,40,42],convinc:[16,50],cook:50,cook_tim:50,cook_time_sec:50,cool:[5,38,40,50],cool_enough:38,cooper:[],coord:40,coordin:[40,41],copi:[5,15,28,29,38,41,42,43,45,48,49,50],core:[38,50],core_color:[],corner:[16,50],coroutin:[],correct:[5,9,16,17,35,40,41,43,45,49,50],correctli:9,correspond:44,corrupt:5,cortext:50,cos:[30,48],cosmologist:47,cost:[5,8,30,36,38,40,41,42,43,48,50],couch:5,could:[5,11,15,16,17,29,30,35,36,37,38,39,40,41,42,43,44,46,48,49,50],couldn:[16,42],count:[16,38],count_down:48,countdown:[],counter:[16,42],counti:[],countri:[5,38,40],coupl:[28,36,38,41,42,43,50],cours:[16,44],cover:16,coward:16,cpu:[16,38,50],cpython:50,crack:[],craft:8,crank:50,crash:[9,37],creat:[0,5,6,8,11,12,15,16,17,31,35,36,38,39,40,41,43,44,45,46,48,50],create_burst:38,createel:[],creation:36,creativ:[],credenti:[16,37],cri:[16,17],criteria:38,criterion:38,critic:5,crockford:5,cross:36,crucial:16,crumb:39,crush:5,cry:[16,17],crypto:37,cryptographi:37,crystal:[],cscope:[],ctag:[],ctor:42,ctrl:[15,42,43],cued:[],cult:5,cultur:[5,16,36],cunningham:49,curat:[5,42],curiou:[],current:[0,8,9,16,36,38,41,43,46,50],current_numb:38,curs:43,custom:[6,39,41,42,43,46,48,50],customiz:41,customizabl:[],cut:16,cwec:41,cyan:[],cycl:[8,11,13,16,36,38,39,42,50],cyphertext:37,daemon:[39,42,46,50],dag:50,dai:5,daili:40,damag:[16,38],damn:[],danc:16,danger:[16,42,48],dark:[16,40],dash:[40,41],data:[8,9,15,16,27,36,38,40,41,42,43,45,49,50],data_readi:38,databas:[40,48],datastructur:[],date:[16,29,42,43],datetim:[31,38,42,43,50],daunt:5,dave:41,david:[5,8,16,36,38,40,41,50],daydream:50,dd2c00:[],dead:[16,17,36],deaden:[],deadlin:37,deadlock:[5,50],deal:[30,38,39,48],dealt:41,dean:50,debt:50,debug:[11,16,28,37,40,41,42,43,44,46,49,50],debugg:[40,41,50],deceit:17,deceit_in_detail:[16,17],deceit_in_detail_tact:16,decent:[16,29,40,42,43],decid:[16,37,39,40,41,46,50],decim:50,decis:[16,36,40,41,50],declar:[37,42],decod:[37,40],decomposit:41,decompress:40,decor:[4,14,37,39,42,43,46,49,50],decoupl:[5,50],deep:[8,38,50],deeper:[41,42,50],deepest:[],deepli:[41,44],deer:[],def:[6,9,10,11,12,16,17,25,26,35,37,38,39,40,41,42,43,44,46,48,49,50],default_lookup_file_url:40,default_nam:42,defeat:16,defeat_in_detail_tact:16,defend:5,defens:5,defer:[0,4,8,11,12,13,16,17,27,28,35,37,39,40,41,43,44,46,49,50],defi:42,defin:[6,8,9,11,12,16,29,37,38,39,40,41,42,43,45,46,49,50],definit:[41,42],deg:40,degre:[38,40],deisgn:[],del:42,delai:[8,12,40,41,42,48,49,50],delay_in_m:50,delay_one_second:[12,42],delay_tim:[16,17],delayed_one_second:[12,42],delet:[38,40],delic:5,deliv:16,deliver:[],delusion:50,delv:16,demo:41,demonstr:[5,16,36,37,38,41,49,50],depend:[5,16,34,41,48,49,50],deploi:[44,45],deploy:45,depth:9,dequ:[0,8,38,50],deque_depth:42,deriv:[16,42,50],desc:50,descend:[38,41,50],descent:[],describ:[4,5,8,9,16,28,29,31,35,36,38,39,40,41,43,44,46,49,50],descript:[15,16,27,36,38,40,41,42,49,50],descriptor:[42,48],deseri:6,design:[4,5,8,9,10,15,18,19,20,21,22,23,29,36,38,39,40,41,42,46,47,49],desir:[12,16,38,42],desk:[30,48],desktop:[],despit:[5,36,38,50],destination_ip:37,destination_port:37,destroi:[16,37,41,44,50],destroy_this_chart:41,destruct:[],destructor:[15,42,43,44],detail:[8,17,27,35,36,38,39,40,42,46,50],detect:[15,38,42,43,44],deterim:38,determin:[8,9,16,26,28,36,38,39,41,43,46,50],determinist:[30,48],deterministicli:[],develop:[5,16,30,36,39,40,41,42,48,49,50],deviat:50,devic:[8,16,39],diagram:[4,8,9,10,15,16,31,33,35,36,37,38,39,40,43,44,46,49,50],dialogu:50,diamond:[40,41],dict:[26,40,42,43],dictionari:[6,16,26,40,42,43],did:[4,5,16,35,36,38,39,40,41,42,46,49,50],didn:[8,16,36,37,38,39,40,41,42,45,46,50],didt_advance_war_cri:[16,17],didt_entri:[16,17],didt_exit:[16,17],didt_init:[16,17],didt_other_advance_war_cri:[16,17],didt_other_ready_war_cri:[16,17],didt_other_retreat_ready_war_cri:[16,17],didt_other_retreat_war_cri:[16,17],didt_other_skirmish_war_cri:[16,17],didt_retreat_war_cri:[16,17],didt_second:[16,17],didt_senior_advance_war_cri:[16,17],didt_skirmish_war_cri:[16,17],die:16,diff:[16,50],differ:[0,4,5,8,9,10,11,15,16,24,36,37,38,39,40,41,42,43,44,45,46,48,49,50],differenti:[16,36],difficult:[8,36,38,40,46,48,50],difficulti:49,difficultli:38,dig:[38,43],digit:[36,42,50],dimens:[16,50],dimension:16,diminish:16,direct:[16,17,36,41,50],directli:[8,16,35,38,39,40,41,42,44,48,50],directori:[9,16,41,45],disarm:38,disast:36,discard:5,disciplin:43,disconnect:37,discov:[8,9,16,17,49,50],discoveri:[5,16,50],discrib:[],discuss:[38,50],disk:[],disord:16,disorgan:16,dispatch:[0,4,8,9,16,17,37,38,42,46],dispatch_graph_a1_s1:9,dispatch_graph_f1_s0:9,dispatch_graph_f1_s22:9,dispatch_to_all_empathi:16,dispatch_to_empathi:16,displai:[42,46,50],disprov:44,disregard:42,distanc:[16,36],distil:41,distinct:[16,38],distinguish:[6,31,42,43,49,50],distort:5,distract:16,distribut:[16,38],div:[],dive:36,diverg:[],divid:[],do_noth:49,dobb:[37,45],doc:[37,38,41,45],doc_process:41,dock:50,docstr:[9,50],documen:[],document:[5,8,9,15,16,35,37,38,40,41,42,43,45,50],dodg:16,doe:[0,8,9,16,28,29,38,39,40,41,42,43,44,45,46,48,49,50],doesn:[5,6,8,9,11,16,36,37,38,39,40,41,42,43,44,46,48,50],dogfight:5,dogmat:5,doh:16,doing:[8,16,28,31,36,38,39,41,42,43,44,46,50],dollar:5,domain:50,domin:5,don:[8,9,11,12,15,16,27,30,36,37,39,40,41,42,43,44,45,46,47,48,49,50],done:[5,16,30,38,39,41,42,45,46,48,49,50],done_buzz_period_sec:50,done_wat:40,doom:16,door:[10,38,41,50],door_clos:[10,38,41,50],door_closed_bak:38,door_closed_init:38,door_closed_off:38,door_closed_open:38,door_closed_toast:38,door_open:[10,38,41,50],door_open_clos:38,door_open_entri:38,door_open_exit:38,dot:[8,16,38,39,40,42,44,46,50],dotenv:16,doubl:[41,42,50],doubt:16,dougla:5,dove:5,down:[12,16,30,36,37,38,39,40,41,42,43,46,48,49,50],download:[40,48],downsid:[],downward:50,draconian:16,draft:[],dragon:[],draw:[8,9,16,35,36,38,44,46,50],drawit:42,drawn:[9,37,41,42,50],dreari:43,drew:36,drift:[42,50],drill:[8,38,41],drink:[16,17,50],drive:[16,38,41,50],driven:[9,36,38,41,50],driver:[41,50],drone:[],drop:[5,16,28,41,42,43,50],drown:[16,41],drum:16,drunk:50,dry:[8,15,16,42,43,45],dtdakkeosog:[],dtype:[],due:[6,16,36,40,50],dumber:16,dump:6,durat:[39,42,50],dure:[6,8,9,16,41,48,50],duti:[38,41,42,50],dynam:[6,16,28,38,39,41,42,43,46,50],e_funct:44,each:[0,5,6,8,9,15,16,17,27,29,31,36,37,38,39,40,41,42,43,44,46,49,50],eae:41,ear:50,earli:[36,42,50],earshot:16,earth:50,easi:[8,16,29,30,35,36,38,39,41,42,43,44,46,48,49,50],easier:[5,15,16,26,38,39,40,42,43,49,50],easiest:[42,47],easili:[16,36,38],easy_bak:38,eat:[41,48],eco1:[],eco2:[],eco:[],econom:36,ecosystem:50,edg:[41,42,50],edit:[5,8,38,40,41,42,44],editor:[5,15,42,43,50],educ:46,edward:16,effect:[8,15,16,38,41,42,43,50],effort:[15,16,30,38,41,42,43,45,48,50],effortless:[],effortlessli:42,eight:[],einstein:41,eioglterpeo:41,either:[5,8,16,17,38,41,42,44,46,50],elabor:50,elaps:[40,50],electr:[8,38,40],element:[8,9,10,38,39,42,50],elev:42,elif:[8,9,10,11,12,16,17,25,38,39,41,42,44,46,49,50],ellison:50,els:[8,10,11,12,16,17,25,36,37,38,39,40,42,43,44,46,49,50],elsewher:[37,40,42,50],email:[36,42,50],emb:41,embed:[5,9,38,39,40,41,43,50],embed_load:[],emerg:[16,42],emit:37,emot:41,emotion:41,empath:16,empathet:16,empathi:[16,17],empathy_for_first_broth:16,empathy_nam:[16,17],emphas:[36,39,41],emphasi:[],empir:36,employe:[],empt:8,empti:[16,46],emptiv:[],enabl:[4,16,41,42],enable_snoop_spi:16,enable_snoop_trac:16,enact:[],enammour:[],enamor:[],enclos:[37,41,50],encod:37,encompass:16,encount:[5,16,50],encourag:50,encrypt:[16,37,42,45],end:[0,8,16,27,31,36,38,39,40,41,42,43,46,50],enemi:[5,16,17,48],energi:38,energy_gener:38,energy_generation_init:38,engag:[16,50],engin:[5,9,36,38,41,42,43,49],english:[16,38,41,50],enjoi:50,enlist:38,enough:[9,16,17,30,36,37,38,39,41,42,44,46,48,49,50],enrag:16,ensur:[0,16,35,37,39,49,50],enter:[9,12,16,17,35,38,39,41,42,44,45,46,50],enthusiast:50,entir:[16,36,40,42,49,50],entireti:43,entiti:[],entrepreneur:50,entri:[4,8,9,11,16,35,38,39,41,44,46,49,50],entropi:[],entry_sign:[6,8,10,11,12,16,17,25,26,27,28,35,37,38,39,40,41,42,43,44,46,49,50],enumer:[6,8,50],env:[16,45],env_path:16,enviro:[],environ:[16,36,45,50],envis:[],equal:40,equat:[16,30,48],equip:[16,50],equival:[16,39,50],era:46,ere:[],ergod:16,ergot:16,erlang:45,erron:16,error:[38,40,42],escap:[16,38],especi:[16,38,50],essenc:38,essenti:[36,48],estim:40,etc:[8,36,41,42,45,50],etho:50,evalu:[35,38,44],evapor:40,evaporatli:[],even:[12,16,36,38,39,41,42,45,46,49,50],event:[0,1,4,5,8,9,10,11,12,13,15,16,17,26,27,28,31,35,36,39,40,43,46,48],event_1:42,event_2:42,event_a:0,event_b:0,event_or_sign:0,event_reset_chart:46,event_wait_complet:46,eventu:[41,42,50],ever:[5,16,37,38,41,42],everi:[4,5,8,16,17,30,37,38,40,41,42,48,50],evermor:[],everyon:[16,36,38,41,43,50],everyth:[0,16,29,35,41,42,43,50],everywher:45,evid:[16,42,44,50],evolv:[36,50],evt:48,evt_a:41,exact:[28,42,43,50],exactli:[5,9,16,35,40,44,48,49,50],exam:[],examin:[39,40,44,50],exampl:[0,2,3,4,6,8,9,18,27,28,29,30,31,33,36,38,40,41,42,43,44,45,48],example1:[],example2:[],examplestatechart:4,exce:[],exceed:40,excel:45,except:[5,8,16,37,39,40,42,45,50],exception:16,exchang:[5,36,37],exchange_declar:37,exchange_typ:37,excit:50,exclud:38,exclus:37,execult:[],execut:[0,5,9,16,36,41,44,48],exercis:16,exert:16,exhaust:[39,46,50],exist:[6,8,16,36,39,40,41,42,50],exit:[0,4,8,11,16,35,37,38,39,41,44,45,46,49,50],exit_sign:[8,10,11,12,16,17,25,26,27,35,37,38,39,40,41,42,43,44,46,49,50],expand:[],expans:[],expect:[16,30,35,36,37,38,39,40,42,44,46,48,49,50],expected_empathy_target_trac:16,expected_empathy_trac:16,expens:[5,8,36,38,43,50],experi:[16,38,43,44],experienc:[16,38,42,49],experiment:16,expertli:16,explain:[0,15,16,35,36,38,40,41,42,44,50],explan:[37,47,50],explicit:[8,38,42,48],explicitli:[8,16,38,42,48,50],explor:50,explorequeri:[],exponenti:43,expos:[16,30,48],express:[5,6,16,36,39,40,41,42,50],extend:[8,9,16,36,37,38,49],extens:[6,8,11,42,45],extern:[0,8,16,36,38,39,41,50],extract:[38,40,42],extraordinarili:50,extrem:[5,16,30,36,41,42,48,50],extrud:[],eye:50,eyebal:[],eyes:[16,41,44,46,50],fabric:[1,8,35,42,46],fabric_task_ev:0,face:[16,42,43,47,50],facil:[38,46],facin:[],fact:[5,16,38,39,41,43,47,50],factor:8,factori:[5,7,8,14,16,17,35,37,38,40,41,43,50],factory_class_exampl:49,factory_class_recipe_exampl:42,factory_in_class:[],factoryinstrumentationtolog:42,fad:41,fade:50,fail:[9,28,38,41,42,43,50],failur:36,fairli:16,fake:[15,16,38,42,43,50],fake_black:[],fake_new:38,fake_transduc:38,fake_whit:[],fakenewsspec:38,fall:[42,50],fall_through:41,fallaci:41,fallen:41,fals:[16,38,40,41,42,44,50],falsifi:47,fame:[],famili:[16,36,48],familiar:[38,39,42,44],famous:5,fanci:[],fanout:37,far:[16,42,44,45,50],farc:50,fashion:36,fast:[16,36,38,50],faster:[16,42,50],fastest_tim:38,father:16,fathom:16,favor:[38,41],favour:16,fb11:35,fb1:35,fc1:[35,42,49],fc2:[35,49],featur:[8,9,15,16,36,37,38,40,41,42,43,48,50],fed:[16,38,50],feder:42,feed:[16,37,40,41,42],feedback:[5,16,50],feel:[5,16,36,37,38,39,41,42,44,50],feign:[16,17],feigned_retreat:[16,17],fellow:50,fermet:37,fernet:37,few:[5,16,36,38,42,50],feynman:47,ff6d00:[],ff6doo:[],ffa501:[],ffff00:[],ffffff:[],ffmpeg:[],fft:41,fiction:[],fidel:[16,50],field:[16,17,38,47],fifo:[0,8,12,16,35,39,41,50],fifo_queu:0,fifo_subscript:0,fig:[],fight:[16,41,42],fighter:[5,36],figur:[16,35,38,39,42,45,46,50],file:[8,16,24,37,40,42,45,50],filenam:42,fill:[11,16,37,38,39,42,45],film:[],filter:[5,38,42],final_icon:41,final_icon_example_1:41,finaliconexampl:41,find:[2,5,8,9,16,30,36,38,39,41,42,48,49,50],findal:50,fine:43,finish:[8,16,38,39,40,41,42,48,50],finit:[8,41],fire:[11,12,16,17,38,39,40,42,46,50],firm:[36,44],firmwar:[5,36],first:[0,6,8,9,13,15,29,30,31,36,37,38,39,40,41,42,43,46,47,48,49,50],first_brothers_nam:16,first_name_of_oth:16,firstscripttag:[],fit:[16,40,41,42,50],five:[16,40],fix:[16,28,42,43,50],fixat:16,flag:[30,48],flank:16,flash:39,flashlight:[],flat:[8,16,38,49,50],flatten:[42,49],flavor:[],flexibl:[16,38],fli:50,flip:50,float32:[],floor:39,flow:[40,42],flower:[],floweri:[],fly:[],fn_parent_state_handl:9,fn_state_handl:9,focu:[16,40,49,50],focus:[16,36,39],fodder:5,fog:16,folder:[16,41],folk:40,follow:[5,6,8,9,15,16,29,30,31,35,37,38,39,40,41,42,43,45,46,48,49,50],font:[],foo:4,food:50,fool:[38,47],foot:41,footman:[16,17],footmen:16,footprint:50,forc:[5,16,38,40,42,46],forecast:[],foreign:[24,37],foreign_hsm:37,foreign_spy_item:37,foreign_trace_item:37,foreseen:16,forev:[0,27,42,43],forget:[39,44],forgot:35,fork:41,form:[8,16,37,38,41,42],formal:[5,8,16,36,38,39,41,42,43,49,50],format:[8,10,16,17,26,37,38,40,41,42,43,50],former:5,forth:[16,50],forward:[30,36,38,41,42,48],found:[2,4,7,9,16,38,42,45,46,50],foundat:50,founder:[],four:[44,48,49],fowler:41,fr_entri:[16,17],fr_exit:[16,17],fr_other_retreat_war_cri:[16,17],fr_out_of_arrow:[16,17],fr_retreat_war_cri:[16,17],fr_second:[16,17],fragil:[16,41],fragment:36,frai:16,frame:[16,37,49],framebord:[],framework:[5,8,36,38,39,42,43,49,50],frankenstein:36,free:[5,36,38,42],freez:50,frequenc:39,fresh:38,fresh_api_cal:40,fridai:[],friedrich:39,friend:[],friendli:38,frighten:39,from:[0,4,5,6,8,9,10,12,15,16,17,24,26,27,29,30,31,35,36,37,38,39,40,41,44,46,48,49,50],from_list:[],front:[0,8,16,36,42,50],frustrat:[16,50],fsm:[8,41],fstring:42,fuck:5,fuction:[],fuel:[5,38],full:[0,4,16,17,27,28,37,38,39,42,43,46,50],fullfil:[],fun:[9,10,11,12,16,17,25,38,39,41,42,44,46,49,50],funcanim:[],functool:[37,42],fund:41,further:[8,38,41,50],furthermor:[16,38],fusion:38,fusion_act:38,fusion_active_cool_enough:38,fusion_active_entri:38,fusion_and_heat_transf:38,fusion_and_heat_transfer_fir:38,fusion_reactor:38,fusionreactor:38,futil:50,futur:[8,16,28,29,37,40,41,42,43,50],fuzzier:16,gain:[8,36,37,40,41,48],gallop:[16,17],game:[],ganbaatar:[16,17],gandbold:[16,17],gang:[15,42,43],ganssl:5,gantulga:[16,17],garbag:[6,9,42,50],garden:[],gate:40,gather:[],gave:[36,50],gaze:50,gear:38,gearbox:38,gem:[],gener:[5,8,12,15,16,29,31,36,37,38,39,41,42,43,45,49,50],general_state_method:49,genghi:16,geniu:43,geo:[],geometri:8,geopolit:46,gestur:50,get:[5,6,8,9,16,26,29,30,36,38,39,40,41,42,43,44,45,46,48,49,50],get_100ms_from_timestamp:50,get_a_nam:16,get_composite_read:38,get_id_file_from_network:40,get_id_file_from_network_entry_sign:40,get_id_file_from_network_readi:40,get_id_file_from_network_retry_after_network_error:40,get_ip:37,get_my_m:50,get_nam:16,get_readi:50,get_ready_sec:50,get_temperature_read:38,get_weath:40,getelementbyid:[],getelementsbytagnam:[],getenv:16,getlock1:48,getlock2:48,getsocknam:37,getter:[],gibberish:45,gift:[5,36],gil:50,gist:41,git:[16,41],github:[40,41],give:[15,16,17,36,39,40,41,42,43,44,46,48,49,50],given:[0,8,9,12,13,16,26,30,31,35,36,38,39,40,42,43,48,49,50],gl1:48,gl2:48,glanc:[41,50],gland:[],glee:5,global:[5,6,16,41,43,50],glossari:33,glow:[],glyph:[8,16,38,41,50],goal:[16,36,37,40,50],god:50,goddess:50,goe:[16,36,38,41,50],going:[9,16,37,38,39,40,41,42,47,48,50],gone:[12,37,42,50],good:[16,35,36,38,41,42,43,44,47,48,50],googl:36,got:[15,16,38,39,40,41,42,43,44,45,46,50],gotten:[16,29,42,43,50],govern:[5,41],gpio:40,grab:[30,48],grade:[],gradual:48,graffiti:42,grai:[],granit:16,grant:50,grap:[],graph:[8,9,41,42,49,50],graph_e1_s1:9,graph_e1_s2:9,graph_e1_s3:9,graph_e1_s4:9,graph_e1_s5:9,graphic:[41,42,50],great:[5,15,16,35,36,38,42,43,45,50],greater:[5,16,39,42,46,50],greedi:0,green:[40,41,42],greeter:50,grep:42,grid:[],grind:43,grok:44,groov:41,ground:[16,36],group:[16,36,40,42,50],grown:[],gstatic:[],guarante:[5,6,16],guard:[8,41],guard_exampl:41,guarente:[],guess:16,guest:[45,50],guest_password:45,guestpath:[],gui:[16,45,47,50],guid:[40,41,45],guidanc:[],guidenc:[],gun:[16,50],gusto:50,gyroscop:[],gzip:40,hack:[7,35,42,50],hacker:44,had:[5,16,27,35,36,37,39,40,41,42,43,44,46,49,50],hadan:[16,17],hadn:5,hal:50,half:5,halfwai:40,hall:50,halt:[16,17,36],hammer:40,hand:[5,8,16,40,41,42,44,49,50],handi:37,handl:[8,10,11,12,16,17,25,35,38,39,40,41,44,46,49,50],handler:[9,11,16,17,35,37,38,39,40,41,46,49,50],handwav:16,hang:[44,50],happen:[5,6,8,9,16,27,28,30,35,36,37,38,39,40,41,42,43,44,46,50],happi:50,hard:[16,30,37,41,42,44,48,49,50],harden:50,harder:[16,36,41,49,50],hardli:49,hardwar:[5,41],harel:[5,8,16,36,38,39,40,41,42,43,49,50],harm:[5,16],has:[0,5,6,8,9,12,16,17,27,28,29,31,34,35,36,37,38,39,40,41,42,43,44,46,49,50],has_payload:[6,42],hasn:[0,4,6,8,12,16,42,50],hast:5,hate:[8,38],hault:[],have:[0,2,4,5,6,8,9,12,13,14,15,16,26,27,28,29,30,31,35,36,38,39,40,41,44,45,46,48,49,50],haven:[5,16,31,37,38,39,40,41,42,43,44,45,46,48,50],hawk:5,hazard:41,head:[16,38,41,43,49,50],hear:[16,50],heard:[16,17,46],heart:[11,16,38,40,42],heart_beat:40,heartbeat:[],heat:[10,16,38,41,50],heater:[38,50],heater_off:[38,50],heater_on:[38,50],heating_element_off:10,heating_element_on:10,heating_entri:38,heating_exit:38,heating_st:50,heaven:50,heavi:[5,16,38],heavili:[16,50],heed:5,heehaw:50,hei:[],height:[],heirach:[],heirachi:[],held:[42,50],hello:[42,45,46,50],helmet:16,help:[5,16,36,38,41,43,46,50],helper:[9,50],helpless:16,her:50,here:[2,4,5,6,8,11,12,16,27,28,30,31,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],herself:50,hesit:42,heurist:16,hidden:[16,30,36,38,41,42,48,49,50],hide:[37,38,41,42,49],hierach:50,hierarch:[8,16,36,37,39,41,42],hierarchi:[8,9,16,37,39,40,42,44,50],high:[0,5,8,16,29,31,36,38,39,40,42,46,50],higher:[5,16,42,50],highest:[0,16,42,50],highli:[],highlight:[4,16,35,37,38,39,40,41,42,48,49,50],hightlight:[],him:[5,16,17,38,50],himself:16,hint:[16,39],hire:5,his:[5,8,9,16,17,36,38,39,44,49,50],histor:[],histori:[10,16],hit:[12,16,38,42,45],hmm:44,hmtl:[],hod:5,hold:[10,13,16,39,41,42,45,50],holder:[],hole:[],holi:5,hollow:50,hologram:16,holograph:16,home:16,honour:8,hood:50,hook:[4,8,16,27,28,39,41,43],hook_1:42,hook_2:42,hook_example_1:41,hook_example_2:41,hope:[5,16,39,50],hord:16,horizont:[41,50],hornet:16,hors:[7,17],horsearch:[16,17],horseback:16,horsemen:16,horserarch:16,host:45,hostnam:45,hot:35,hour:[41,43],hous:[],how:[1,4,5,8,9,11,15,16,17,25,27,31,35,36,37,38,39,40,41,42,44,45,46,47,48,49,50],howev:[6,9,37,38,39,40,47,49,50],href:[7,18,19,20,21,22,23,36,38,40,41,42,43,47,50],hsm:[0,1,4,8,16,17,36,38,41,49,50],hsm_queues_graph_g1_s01:0,hsm_queues_graph_g1_s1:0,hsm_queues_graph_g1_s2111:0,hsm_queues_graph_g1_s22:0,hsm_queues_graph_g1_s321:0,hsmevent:0,hsmeventprocessor:[9,38],hsmtester:4,hsmtoplogyexcept:38,hsmtopologyexcept:[8,9,38,42],hsmwithqueu:[16,17,37,38],html:[7,18,19,20,21,22,23,36,38,40,41,42,43,47,50],http:[5,40,41],huge:[],hulagu:[16,17],human:[5,41,50],humid:40,humnan:[],hung:16,hunt:16,hurri:39,hypothes:[],hypothesi:[],i_list:50,i_thread_safe_attribut:[],iaf:5,icon:[8,38,40,42,50],id_rsa:45,idea:[5,8,11,16,27,36,38,39,40,41,42,43,46,48,50],ideal:16,ident:[41,48,49],identifi:[16,17,31,37,40,41,42,43,49,50],ideosynchroc:[],idiom:[],idiot:5,idl:[38,40,41],idle_data_readi:38,idle_entri:38,idle_entry_sign:40,idle_get_weath:40,idle_new_request:38,idle_request_city_detail:40,ids:[39,40],ieee:36,ifram:[],iframe_api:[],ignor:[0,6,8,12,16,17,38,39,41,42,44,46,50],ihbarhasvad:[16,17],iir:38,ill:[],illeg:[8,38,44,45],illus:[5,49],illustr:50,imag:[8,15,16,36,41,42,43],imagin:[8,16,30,36,38,41,42,44,48,50],imbu:40,immedi:[5,13,16,17,27,36,38,40,41,42,43,50],immens:[],immut:[6,40,41,42,50],impati:16,impedi:42,implement:[16,36,38,39,40,41,42,44,49,50],implemt:[],implicit:[],implicitli:48,impliment:[],implment:8,importantli:[5,44,49],importerror:50,impos:16,imposs:38,imprecis:16,impress:5,improv:[16,36,40,50],impuls:38,inabl:16,inadvert:41,inbox:16,incent:5,incid:[],incircl:8,includ:[4,16,41,42,45,50],incompet:16,incomplet:41,incomprehens:16,inconsist:48,inconveni:[4,38],incorpor:[],incorrect:42,incorrectli:[8,16],increas:[8,16,38,41,43,50],incred:[],increment:[16,38],increment_x:41,indec:[],independ:[16,38,40,42],indepent:41,index:[9,33],index_and_time_delai:[],indic:[8,9,31,38,41,42,43,50],indirect:49,individu:[16,17,37,38,39],industri:[5,36,39],ineffici:[],inevit:[38,43],inexpen:[],inexpens:[15,40,42,43],inf:[],infect:[],infer:44,infinit:[5,8,11,16,27,38,42,43],inflex:16,inform:[0,5,8,10,16,24,27,29,35,36,38,39,41,43,46,49,50],infra:[],infract:44,infrastructur:[36,42,45],infrastur:[],infrequ:[30,48],inherit:[0,8,9,16,37,38,39,42,46,48,50],init:[4,6,8,9,12,35,38,39,41,42,46,49,50],init_func:[],init_sign:[8,10,11,12,16,17,25,26,27,28,35,37,38,39,40,41,42,43,44,46,49,50],initi:[8,9,16,38,39,41,44,46,50],initial_condition_index:[],initial_st:9,initial_valu:38,inject:[8,16,37,38,42,49],inner:[8,11,12,16,27,36,38,39,41,42,43,46,50],inner_most:42,inner_st:[38,41,42],inner_state_1:41,inner_state_1_b:41,inner_state_1_entry_sign:41,inner_state_1_exit_sign:41,inner_state_2:41,inner_state_2_a:41,inner_state_2_entry_sign:41,inner_state_2_exit_sign:41,inner_state_entry_sign:42,inner_state_exit_sign:42,innner:39,innner_st:[],innoc:[30,48],innocu:[16,48,49],innov:[5,16,36],input:[8,16,37,38,39,40,41,42,50],insert:16,insertbefor:[],insid:[8,16,36,37,40,41,48,50],insight:5,inspect:[35,38,42,50],inspir:[36,38],instal:[16,33,36,37,50],instanc:[8,16,28,37,41,42,43,46,49,50],instanti:[36,38,40,41,42,49,50],instati:[],instead:[0,6,11,16,36,37,38,39,40,41,42,43,46,48,49,50],instruct:[16,44,45,50],instructor:5,instrument:[0,7,8,10,16,27,31,35,36,37,38,39,40,41,43,46,47,49,50],instrumentation_line_of_match:50,instrumentedfactori:[40,41],insur:50,intact:16,intang:16,integ:16,integr:[16,36,41,50],intellig:16,intend:[5,8,16,37,38,42,50],intens:[],intent:[16,36,38,41,42,50],intention:42,inter:[],interact:[4,5,7,9,15,16,39,40,41,42,43,46,48,50],intercept:38,interconnect:50,interest:[5,16,35,36,37,42,50],interfac:[6,16,36,37,40,41,42,50],interleav:[15,42,43,50],interlock:41,intermedi:[41,50],intermediari:[],intern:[0,6,7,8,16,18,19,20,21,22,23,27,30,36,38,40,41,42,43,46,47,48,50],internal_signals_1:41,internet:[37,42,45],interplai:[42,46],interpret:[40,50],interrel:50,interrupt:[5,38,41,46],interv:42,intervent:43,intial_condition_index:[],intimid:50,intric:16,intrins:[],intro_1:[],introduc:[16,27,30,37,38,42,43,48,50],introduct:[33,40,45],introspect:[16,17],intuit:[16,42],invent:[5,8,16,36,38,40,41,50],invers:[5,39,49,50],invert:9,invest:[41,50],investig:39,invis:[],involv:[16,35,36,38,50],inward:50,iot:36,ips:[16,17],is_al:41,is_fil:16,is_in:9,is_set:48,is_this_piston_readi:38,is_wint:40,ish:16,isn:[5,6,13,16,17,36,41,42,46,50],iso:40,isol:[42,43,50],isra:[5,36],issu:[8,16,17,28,29,30,37,38,40,42,43,46,48,49,50],item:[0,6,8,9,16,17,26,31,37,38,39,40,42,43,44,46,50],iter1:[18,19,50],iter2:[19,20,50],iter3:[20,21,50],iter4:[21,22,50],iter5:[22,23,50],iter6:[23,50],iter:[16,38,41,48],its:[0,4,5,8,9,15,27,30,31,35,36,38,39,40,41,42,43,45,46,48,49,50],itself:[8,16,37,38,39,40,41,42,43,44,46,48,49,50],jack:5,jacket:50,java:[41,50],javascript:[5,41],jersei:5,jet:[5,36],jinja2:[8,45],jinja:8,jitter:50,jitteri:[30,48],job:[29,39,42,43,45,50],john:36,join:[16,41,48,50],joke:16,journal:39,journei:50,json:[5,6,40,50],json_ev:6,juggl:50,jump:[9,16,36,39,50],june:36,junior:16,jupyt:50,just:[5,6,9,11,16,26,28,29,35,36,37,38,39,40,41,42,43,44,45,46,49,50],kai:[36,40,42],keel:36,keep:[0,9,16,36,37,38,39,40,41,42,44,45,48,49,50],kei:[5,16,26,35,37,40,42,43,45],kept:[38,50],keygen:45,keyword:[],khan:16,kill:[0,5,16,39,42,46,50],kill_tim:48,killer:48,kind:[8,13,16,30,38,39,40,41,42,46,48,50],kkk:[],knew:[37,38,46,50],knight:[16,17],know:[5,8,9,11,12,15,16,35,36,37,38,39,40,41,42,43,44,45,46,49,50],knowabl:50,knowledg:[16,40,50],known:[],korean:16,kwarg:[6,9,42],label:[9,15,39,41,42,43,46],laberg:38,lac:9,lack:[16,47],lag:16,lai:[39,50],laid:[],lame:50,lamp:38,lamp_off:38,lamp_on:38,lan:16,lanchart:41,land:[41,50],languag:[5,8,16,36,38,41,45,49],lanreccechart:41,larg:[8,9,16,36,38,41,42,46],larger:[5,16],larri:50,last:[0,8,16,35,38,40,42,46,48,49,50],last_brothers_nam:16,lastli:[],lat:40,late:[5,36,50],latenc:50,later:[9,16,37,38,39,42,50],latest:[5,16,36],latex:43,law:[5,50],layer:[16,42,49,50],lazi:[42,50],lca:[9,50],lead:[16,38,50],leader:16,leadership:[5,16],lean:[16,50],leap:[],learn:[5,7,8,16,35,38,41,42,46,50],least:[9,16,38,40,42,45,49,50],leav:[4,8,9,12,16,36,38,39,40,41,42,46,50],led:36,left:[8,16,17,37,40,41,49,50],left_wal:[],leftmost:0,legal:[],legend:50,legibl:[16,50],leisur:16,len:[16,26,37,42,43],length:9,less:[16,17,36,38,41,42,46,49,50],let:[5,10,16,17,35,36,37,38,39,40,41,42,44,46,48,49,50],letter:36,level:[5,8,16,29,31,38,39,40,42,46,50],levelnam:42,lib:[],liber:36,librari:[1,5,8,16,30,34,35,36,38,39,40,41,42,45,46,48,49,50],licenc:[],lie:16,lies:[],life:[38,42,50],lifelin:41,lifetim:[5,47],lifo:[0,8,12,41],lifo_queu:0,lifo_subscript:0,lift:[],lighlight:[],light:[10,16,36,40,41,44,50],light_off:50,light_on:50,lightweight:41,like:[5,8,9,11,12,13,15,16,26,27,29,30,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],likewis:[16,40,46,50],limbo:44,limit:[9,16,37,40,41,42,50],limp:[],line:[8,16,28,29,31,35,36,37,38,39,40,41,42,43,44,46,48,49,50],linear:[16,41,42],linearsegmentedcolormap:[],lineno:[],ling:[],linger:16,link:[16,35,36,38,39,40,41,42,43,45,46,49,50],lint:5,linux:[37,50],lion:[],lip:[],liquid:38,list:[0,6,9,16,17,36,38,39,40,42,44,48,50],list_spi:50,listen:[16,37,42],listless:50,liter:49,lithium:38,litter:[],littl:[5,15,16,35,38,39,40,41,42,43,44,48,50],live:[5,8,16,37,38,40,41,50],live_spi:[16,37,40,41,43,50],live_trac:[10,16,37,40,41,42,43,50],load:[6,16,17,40,44,50],load_dotenv:16,lobotom:16,local:[8,16,17,37,38,40,45,48],local_consum:37,localconsum:37,localhost:45,locat:[0,8,9,16,37,38,40,41,42,50],lock:[0,5,16,30,40,41,42,43,48,50],lockhe:5,lockingdequ:0,log:[8,11,16,25,27,31,36,38,39,40,41,42,43,44,45,46,49,50],log_file_nam:42,logger:[],logic:[16,42,44,50],login:45,lon:40,longer:[16,38,41,42,44,50],look:[5,8,12,16,28,29,31,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],lookup_file_nam:40,lookup_file_path:40,lookup_file_url:40,lookuperror:[],loop:[0,15,16,36,39,41,42,43,46,50],loos:[8,16,38],loosen:16,lorenz:16,lose:[16,36,43,50],loss:16,lost:[16,36,41,49],lot:[5,8,15,16,35,36,38,39,40,41,42,43,45,46,48,49,50],lotteri:[],loud:16,love:[38,41,50],low:[16,17,39,42],lower:[0,5,41,42,50],lowest:[42,50],luck:[5,50],lucki:36,lure:[16,17],mac:[],machin:[6,7,8,10,16,24,36,37,38,39,41,44,45,48,50],machine_cl:[],macho:[],macro:[42,48],made:[5,8,16,30,35,36,38,40,41,42,45,48,49,50],magnet:38,mai:[16,41,42,43,50],maim:16,main:[0,10,16,30,37,39,40,41,42,48,50],mainli:16,maintain:[5,16,37,41,49],mainten:[5,30,36,42,48,49,50],maintenc:8,major:[5,36,41],make:[5,6,8,10,11,13,15,16,17,26,30,35,36,38,39,40,41,43,45,46,48,49,50],make_and_start_left_wall_machin:[],make_and_start_right_wall_machin:[],make_generation_coroutin:[],make_test_spec:50,make_unique_name_based_on_start_at_funct:0,make_url:40,malevol:16,malform:9,man:[5,16],manag:[0,4,5,8,16,29,30,35,36,39,41,42,43,44,45,46,49,50],manageri:[],mandatori:9,maneuv:[16,17],mani:[5,8,11,16,28,36,38,39,40,41,42,43,45,46,48,50],manifest:[8,36,41,50],manipul:[40,42],manner:[8,30,42,43,48,50],manoeuvr:16,manual:[15,38,41,42,43],manufactur:[8,42],map:[8,10,16,17,29,35,36,40,41,42,43,49,50],marbl:[41,42],march:50,marcu:[],margin:[],mari:[6,42,50],mark:[11,15,16,30,35,38,39,41,42,43,45,48,50],markdown:43,marker:42,market:36,markup:[8,42],marshal:[16,17],marshal_entri:[16,17],marshal_readi:[16,17],martin:[5,41],marvel:50,mashup:[],mass:[5,16],massiv:[16,36],master:38,match:[16,41,50],materi:46,math:[30,48],mathemat:[16,36,41],mathematica:[],mathematician:36,mathwork:[],matlab:41,matplot:[],matplotlib:[],matrix:[],matter:[6,16,50],max:[26,42,43],max_index:9,max_name_len:[26,42,43],max_number_len:[26,42,43],maxim:16,maximum:[9,38],maximum_arrow_capac:[16,17],maxlen:0,mayb:[16,38,44,48,50],maywhil:[],mba:[],meali:8,mean:[5,8,9,16,26,27,36,37,38,39,40,41,42,43,44,46,48,49,50],meaning:[16,42],meaningless:50,meant:[8,16,36,46],meanwhil:[36,40,50],measur:[8,36,38,40],meat:16,mechan:[5,16,36,38,41,43,50],media:[],mediev:16,medium:[],meet:[16,37,42,50],member:[16,50],memori:[5,16,27,30,36,38,40,41,42,43,48,49,50],men:16,menac:16,mental:[16,36],mention:[39,42,46,50],mere:[41,42],merv:50,mesh_encryption_kei:16,mess:50,messag:[0,8,12,15,16,25,36,38,40,41,42,43,50],messi:42,met:[38,50],meta:50,metaclass:[42,48],metal:38,metaphor:[16,36,39,50],metaprogram:[41,48,49],method:[0,4,6,8,9,10,16,25,26,31,35,36,37,38,39,41,43,44,46,50],method_1:41,method_2:41,metric:40,michel:38,micro:16,micromanag:[16,50],microsoft:[36,43],mid:[],middl:[5,11,12,27,39,42,43,44,46],middle_st:42,middle_state_entry_sign:42,middle_state_exit_sign:42,middle_state_readi:42,midwai:[30,48],might:[5,8,12,16,27,28,29,36,37,38,39,40,41,42,43,48,49,50],militari:[5,16],millisecond:[30,48,50],mimic:[],mind:[36,40,41,42,44],mine:41,minecraft:8,miner:10,mingu:[],mini:[],minim:[16,45,50],minimalist:50,minimum:[38,40],minion:50,minor:[],minut:[16,40,50],miracl:16,miro:[1,4,5,8,9,10,16,17,26,27,29,30,34,35,36,37,38,39,40,43,44,46,47,48,49,50],miros_rabbitmq:16,mirror:16,misbehav:50,miss:[16,41,42,46,49,50],mission:41,mistak:[16,41,50],mistakenli:16,misunderstood:36,mix:38,mixtur:42,mkdir:45,mnemon:[9,41,50],mobil:16,mock:50,mockup:[],mode:[4,38,50],mode_control:4,model:[8,36,38,39,41],model_control:4,moder:43,modern:[16,36],modifi:38,modul:[1,33,36,49],modular:50,modulo_bas:50,molten:38,momen:8,moment:[0,16,38,41,42,49,50],momentarili:42,momentum:36,mondan:[],monei:[5,36,43,50],mongol:7,monitor:[5,16,24,37,50],month:5,moor:8,moot:43,mordecai:5,more:[0,5,7,8,9,16,30,31,35,36,37,38,39,40,41,43,44,46,48,49,50],moreov:44,morn:40,most:[5,9,16,30,35,38,39,40,42,45,48,50],mostli:[37,41,42,45,50],motiv:50,mount:16,mous:[],mouse_click:41,mouse_click_evt:41,mousecoordin:41,move:[2,9,16,36,37,39,41,42,44,46,48,50],movement:[16,36,50],movi:[],mp4:[],mro:41,much:[5,8,9,16,36,38,40,41,42,44,49,50],mud:16,mulishot:[],multi:[8,11,16,30,48],multi_shot_thread:[11,39,42],multipl:[16,30,31,37,38,40,41,43,45,48,49,50],multishot:[8,40,50],multitask:5,multithread:[40,42],multivers:50,mundan:41,munger:50,must:[6,8,9,16,37,39,41,42,46,47,48],mutabl:41,mute:4,mutex:5,mutual:9,my_ev:41,my_event_with_payload:41,my_hook:42,mypayload:42,myself:[16,42,44,50],n_angl:[],n_mask:[],nag:44,nai:[],name:[0,5,6,8,9,11,14,16,17,26,31,35,36,37,38,39,40,41,43,44,45,46,48,49,50],name_for_sign:[6,26,42,43],name_of_item2:42,name_of_item_1:42,name_of_item_2:42,name_of_sign:42,name_of_state_name_of_ev:42,name_of_subclass:6,namedtupl:[40,41,42,50],namespac:39,nametupl:50,napkin:36,napoleon:16,narankhuu:[16,17],narantuyaa:[16,17],narrow:[],nassim:[35,44],nasti:[40,42,48,50],nativ:[],natur:[6,36,38,41,44,47,48],naviag:[],navig:[9,38,41],nearbi:50,neat:37,necessari:16,necessarili:[],neck:[16,50],need:[0,5,8,9,11,12,15,16,27,28,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],needlessli:[12,42],neg:50,neighbor:[],neither:[],neovim:5,nergui:[16,17],nervou:[16,50],ness:16,nest:[8,16,17,35,37,38,40,41,42,49],net:9,netscap:5,network:[6,9,15,17,36,42,43],network_error:40,network_error_retry_time_in_sec:40,networked_horse_arch:16,networkedactiveobject:16,networkedfactori:16,never:[5,16,30,36,38,39,41,42,48,50],new_machin:[],new_nam:50,new_named_attribut:6,new_request:38,newest:38,newli:[37,45],newlin:37,next:[7,8,16,17,18,19,20,21,22,23,28,34,36,38,39,40,41,42,43,44,46,47,49,50],next_gener:[],next_rtc:0,nice:[40,41,42,49,50],nich:36,nichola:[35,44],nietzsch:39,night:40,night_to_dai:40,night_to_night:40,no_ack:37,noam:45,nobl:41,nobodi:[16,50],node:[16,37,40,41,49],nois:[],noisi:16,nomin:40,non:[10,30,42,43,48,50],nondetermin:5,none:[0,6,8,9,10,16,17,35,37,38,39,40,41,42,44,46,49,50],nonexist:50,nonsens:37,noob:[],normal:4,norman:5,north:16,not_rain:40,not_raining_exit_sign:40,not_raining_init_sign:40,not_raining_st:40,not_wait:[16,17],note:[16,37,40,42,44,50],notebox:[],noth:[0,4,5,8,38,39,40,41,42,46,47,50],nothing_angl:[],nothing_at_row:[],nothing_mask:[],notic:[8,15,16,30,31,36,38,39,40,41,42,43,44,48,49,50],notifi:[16,50],notion:[16,36,41],notit:[],now:[5,9,12,15,16,35,37,38,39,40,41,42,43,44,45,46,48,49,50],nsa:42,nuanc:42,nuclear:38,number:[6,8,11,15,16,26,27,31,35,38,41,42,43,46,48,50],numer:16,numpi:38,nutshel:50,nvu8m8a73jg:[16,37],oadp1sh69j:[],obei:16,obj:6,object:[1,5,6,8,9,11,15,16,26,27,28,29,30,31,35,36,38,39,40,41,43,44,48,49,50],oblivion:50,obscur:5,observ:44,obtain:[15,37,42,43,48],obviou:[16,35],obvious:[],occur:[8,9,16,27,30,31,36,38,39,40,41,42,43,46,48,50],occurr:[],od647c:[],oddli:50,off:[10,12,13,16,38,39,40,41,42,49,50],off_entri:38,off_press:41,offer:[37,42,50],offic:[16,17],officer_lur:[16,17],offset:50,often:[8,16,36,38,41,42,50],oha:[16,17],oha_1:16,old:[0,16,27,36,40,42,43,46,49,50],old_left_machin:[],old_machin:[],old_right_machin:[],oldest:[8,38,39,42],onc:[6,8,9,11,16,17,27,38,39,40,41,42,43,45,46,50],one:[0,5,6,8,9,11,12,13,15,16,18,24,30,31,36,37,38,39,40,41,43,45,46,47,48],onedcellularautomatawithanglediscoveri:[],onedcellularautonomata:[],ones:49,oneshot:50,onli:[0,5,9,11,14,16,29,31,34,36,37,38,39,40,41,42,43,44,45,46,48,50],onlin:42,onplayerreadi:[],onplayerstatechang:[],onreadi:[],onstatechang:[],onto:[0,5,8,15,16,35,36,37,38,39,40,41,42,43,45,50],onyoutubeiframeapireadi:[],onyoutubeplayerapireadi:[],oop:[36,44],open:[10,36,38,40,41,42,45,50],open_weather_map_city_detail:40,openweathermap:40,openweathermapcitydetail:[],oper:[5,8,16,30,36,38,40,42,46,48,50],oppon:16,opportun:[16,48,49,50],oppos:[5,16,36],opposit:[5,16],optim:[],option:[8,9,16,42,45],optionalpayload:41,orang:[],orb:50,order:[8,16,17,38,40,43,44,50],ordereddict:6,ordereddictionari:[26,42,43],ordereddictwithparam:6,org:40,organ:[16,38,43,49,50],orient:[36,38,40,41,42],origin:[0,8,12,16,36,38,42,44,48,49,50],orthogon:[4,8,16,36,40,50],oscil:[16,48],oscilloscop:50,other:[0,5,8,9,11,15,16,17,26,27,28,30,35,36,37,38,39,40,41,45,46,47,48,49,50],other_advance_war_cri:[16,17],other_archer_nam:16,other_arrival_on_field:16,other_inner_most:42,other_ready_war_cri:[16,17],other_retreat_ready_war_cri:[16,17],other_retreat_war_cri:[16,17],other_skirmish_war_cri:[16,17],otherhorsearch:[16,17],otherwis:[8,9,16,28,36,38,40,41,42,43,44,49],our:[0,5,9,10,12,13,28,29,30,35,36,38,39,40,41,42,43,45,46,47,48,49,50],ourselv:[16,38,40,42],out:[0,5,6,8,9,10,13,16,17,27,29,35,36,37,38,39,41,42,43,44,45,46,48,49,50],out_of_arrow:[16,17],outag:40,outcom:5,outer:[8,11,12,16,27,38,39,41,42,43,46,50],outer_st:[38,41,42],outer_state_broadcast:42,outer_state_entry_sign:[41,42],outer_state_exit_sign:42,outer_state_hook:[41,42],outer_state_init_sign:[41,42],outer_state_reset:42,outer_state_retri:41,outer_state_send_broadcast:42,outermost:[41,42,50],outmost:[],output:[0,8,9,15,16,26,27,28,29,31,35,38,39,40,41,42,44,46,48,49,50],outsid:[8,9,12,13,16,17,30,36,38,39,40,41,42,44,46,48,50],outsourc:[],outward:[8,9,16,38,41,42,50],outwardto:[],outweigh:50,oval:50,oven:[10,38,41],oven_off:6,over:[0,4,5,8,9,16,28,29,35,36,37,38,39,41,42,43,44,45,49,50],over_off:6,overal:16,overemphas:36,overflow:[37,38],overli:42,overload:[38,41],overrid:38,overtak:[],overwhelm:[16,39],overwrit:[38,43],overwritten:[9,39],owm:40,own:[2,5,8,16,30,36,38,39,40,41,44,45,48,49,50],oxymoron:41,p27:[],pack:[5,16,35,41,42,46,49,50],packag:[8,16,36,41,42,50],packet:[],pact:[],page:[5,16,33,35,36,40,41,44,45,50],paglia:46,pai:[4,5,16,35,38,39,41,42,50],paid:5,pain:[5,45],paint:50,pair:50,pale:5,palett:41,pallet:41,pantri:38,paper:[8,30,36,38,39,42,46,48],paradigm:39,paradox:16,paragraph:[46,50],parallel:[36,39,42,43],paramet:[6,37,50],parameter:50,parameteriz:[],parametr:16,paramount:16,parent:[8,9,16,17,35,37,38,40,41,46,49,50],parent_callback:[8,49],parent_state_of_this_state_method:42,parentnod:[],pariti:6,pars:50,parsimoni:36,part:[0,4,9,10,11,16,17,30,36,37,38,39,40,41,42,44,45,46,48,49,50],partial:[41,42],particip:[16,43,50],particular:[5,41,42,43],particularli:[44,50],partnership:41,pass:[6,8,12,16,17,30,36,37,38,39,41,44,46,48,50],passphras:45,password:45,past:[15,36,41,42,43,44],patch:41,path:[8,9,16,40],pathlib:[16,40],pathwai:[16,42],patient:50,pattern:[4,7,8,16,33,36,37,39,40,41,42,46,47,50],paus:[],payload:[6,8,16,17,31,35,38,40,43],payment:36,pcolormesh:[],pdb:[28,42,43],pdf:[40,50],peachi:[29,42,43],pedant:5,pencil:42,pend:[0,6,16,29,42,43,46,49,50],pending_on_piston:38,pending_on_pistons_timeout:38,pending_optimal_condit:38,pentagon:5,peopl:[5,16,30,36,38,41,48,50],pepper:[16,39,41,50],per:[8,16,17,39,40,42,47,50],percent:[5,16,17,40,50],percol:41,percul:[],perfect:[16,42],perfectli:[],perform:[5,9,16,17,36,38,39,40,41,42,44,45,48,49,50],peril:5,period:[0,8,11,12,16,17,38,39,40,42,50],peripher:[16,36,40],permiss:[44,45],permit:[16,50],permut:[],pernici:[],perpetu:[],persist:50,person:[16,30,36,41,44,47,48,49,50],perspect:36,peter:[16,50],pgn:[],phase:[42,46,50],phenomenon:16,philosoph:[36,44],philosophi:50,phoenix:46,phrase:50,phsysic:[],physic:[8,38,50],pic:37,pick:[5,16,30,48,50],pickl:6,pico:45,pictori:[],pictur:[15,16,35,36,37,40,41,42,43,46,47,50],piec:[5,30,46,48,50],pierr:[5,35],pigment:[],pika:[37,45],pilot:5,pin:[40,50],pioneerrequest:42,pioneerrequestspec:42,pip3:37,pip:[34,50],pis:[],piston:38,piston_1:38,piston_:38,piston_act:38,piston_manag:38,piston_numb:38,piston_readi:38,piston_slam:38,pitch:41,pivot:50,place:[0,4,8,9,13,15,16,29,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],placement:41,plai:[4,16,42,48,50],plain:[8,16,41],plain_text:37,plaincredenti:37,plan:[16,38,40,46,50],plane:5,planet:5,plant:[36,40],plasma:38,plastic:[],plate:[41,50],platform:[37,50],playbook:45,player:[],player_api:[],playerstatu:[],playvideo:[],pleas:40,plenti:16,plod:[],ploi:[],plot:[],plt:[],pluck:16,plugin:[16,36,41,42],png:[],pocket:50,point:[5,8,9,15,16,17,28,29,36,38,43,46,48,50],pointless:[36,50],poke:40,pole:38,polici:[16,38],polish:[],poll:38,polling_ent:38,polling_init:38,polling_process:38,polling_time_out:38,polling_time_out_hook:38,polyamor:38,poni:16,pool:[8,38],poorli:[],pop:[0,5,8],popleft:[],popul:9,popular:[36,40,41],port:[5,8,36,37,38,39,40,42,45,50],portabl:50,portal:50,portion:[],pose:42,posit:[38,50],possess:44,possibl:[9,16,36,37,38,41,42,43,45,48,50],post:[0,6,8,12,13,16,27,35,38,40,41,43,46,49,50],post_act:4,post_def:[27,28,38,39,42,43],post_fifo:[0,8,10,11,12,16,17,27,35,37,38,39,40,41,42,43,44,46,49,50],post_id_1:0,post_id_2:0,post_lifo:[8,11,38,40,41,42,50],postul:5,potato:50,power:[5,16,36,38,41,43,50],practic:[5,8,9,35,36,38,40,41,44,50],praction:[],practition:[36,38,41],pragmat:[],pratic:[],pre:[8,16,29,42,43,49,50],pre_time_sec:50,preced:[],precis:[16,48,50],predatori:[],predefin:[41,50],predetermin:[16,38,50],predica:16,predict:[],preemption:5,preemptiv:5,prefer:[16,50],prefix:16,preform:50,prei:16,preliminari:50,prematur:16,prepar:[16,42],prepend:50,prepend_trace_timestamp:50,preprocessor:[48,49],present:[5,8,16,36,38,42,46,50],press:[15,36,42,43,50],pressur:[13,38,40,42],presum:50,pretend:[16,38,39,50],pretti:[16,27,28,42,43,44,45,49,50],prev:[7,18,19,20,21,22,23,34,36,38,40,41,42,43,47,50],previou:[4,16,39,40,41,42,46,49,50],previous:[16,39,46],previous_gener:[],price:[39,40,50],prim:0,prime:[16,38],princip:46,principl:[15,42,43,47],print:[0,4,6,8,10,16,17,26,27,28,29,35,37,38,39,40,41,42,43,46,48,49,50],print_msg:50,print_payload:41,print_str:41,printer:[27,42,43],prion:[],prior:[6,8,12,35,37,38,39,40,42,48],priorit:[],prioriti:[0,5,8,16,35,42,50],priorti:[0,8],privat:[36,45],privileg:39,probabilist:[30,42,48],probabl:[15,16,38,39,41,42,43,50],problem:[5,8,16,29,30,36,38,40,41,42,43,44,45,48,49,50],proce:[16,41,50],procedur:45,proceed:48,process:[5,6,8,9,11,13,16,17,27,30,36,37,38,39,40,41,42,43,45,46,48,49,50],process_a_gener:38,process_a_specif:38,process_b_gener:38,processing_count:38,processing_entri:38,processing_exit:38,processing_init:38,processing_pol:38,processor:[5,8,9,16,27,36,37,38,39,40,42,43,44,46,49,50],produc:[8,16,24,36,38,39,40,41,48,50],producer_192:37,producer_out:37,producer_outer_b:37,producer_outer_init:37,product:[36,38,40,41,43,50],profession:38,profil:[],profit:5,program:[4,5,8,9,10,15,16,26,28,29,30,36,38,39,40,41,42,43,45,46,48,49,50],programat:43,programm:[16,38,50],programmat:[],progress:50,prohibit:50,project:[5,16,31,36,38,40,42,43,50],promis:36,prompt:45,proof:[18,19,20,21,22,23],propag:[38,41,50],proper:40,properli:[8,16,41,42,49],properti:[8,16,36,37,42,48],prophet:35,propos:38,proprietari:36,protect:[5,16,30,42,48,50],protoc:[],protoco:[],protocol:[40,42,48,50],prototyp:[38,40,41,50],protractor:[],prove:[16,50],proven:[5,50],proverb:[],provid:[0,5,6,8,9,11,16,26,35,36,37,38,40,41,42,43,45,46,48,49,50],pseudo:[],pseudost:[8,38,41,42,50],psycholog:[43,44],pub:[0,35,37,42,45,50],pub_sub_exampl:41,publish:[0,5,8,16,35,36,37,40,45,50],publish_bb:35,publishing_ao:42,pull:[5,6,16,17,36,39,40,41,44,46,50],puls:[38,50],pump:[16,38,39],purchas:5,purpl:[],purpos:[24,37,38,42,45,50],pursu:[5,16],pursuit:44,push:[0,16,38,42,44,49,50],put:[0,16,17,30,38,39,40,41,42,43,44,48,50],puzzl:50,pycrypto:37,pydotenv:16,pyplot:[],python3:[42,50],python:[4,5,8,16,26,30,34,36,37,38,40,41,43,44,45,48,49,50],qai9iicv3fkbfruakrm1gh8w51:[16,37],quad:50,quantum:39,quarri:16,quarter:16,queri:[4,40,42,46,50],query_api:40,query_weath:40,query_weather_init_sign:40,question:[15,16,18,19,20,21,22,23,35,36,41,42,43,49],queu:[4,27,28,35,36,37,38,39,40,41,42,43,44,46,49,50],queu_depth:[],queue:[0,8,13,16,35,37,38,39,40,41,42,45,46,50],queue_bind:37,queue_declar:37,queue_depth:42,queue_typ:[0,42],quick:[33,36,41,50],quicker:[],quickli:[16,36,39,41,43,50],quickstart:50,quieter:16,quit:[16,36,37,38],quiver:16,quora:[],quot:[5,38],rabbit123:45,rabbit567:16,rabbit:[16,37,38,45],rabbit_guest_us:16,rabbit_heartbeat_interv:16,rabbit_instal:45,rabbit_nam:45,rabbit_password:[16,37,45],rabbit_port:16,rabbit_producer_192:37,rabbit_us:[16,37],rabbitfactori:16,rabbitmq:[16,36,41,42],rabbitproduc:37,race:[5,16,30,42,48],radar:36,rage:41,raid:[],rain:[16,40],rais:[8,9,50],ran:[24,36,37,38,39,40,42,46,49,50],randint:[16,17,42],random:[16,17,37,38,40,42],random_numb:38,randomli:50,rang:[5,16,38,40,50],rank:16,rap:50,rare:50,raspberri:[16,24,37,40,45,50],rate:[5,38],rather:[8,16,38,39,41,42,43,50],ratio:[],ravel:[],raw:[],raw_weather_lookup_dict:40,raw_weather_lookup_list:40,reach:[8,16,38,39,42,50],reachabl:37,react:[4,8,12,16,27,38,39,40,41,42,43,46,49,50],reaction:[8,13,16,38,39,42,46,50],reactiv:[36,38,42,46],reactor:38,reactor_on:38,reactor_on_entri:38,reactor_on_init:38,reactor_on_prim:38,reactor_on_time_out:38,read:[5,8,9,16,26,27,30,36,38,39,40,41,42,43,45,46,48,49,50],read_fil:40,read_file_entry_sign:40,reader:[],readership:36,readi:[16,17,28,38,39,40,42,43,44,50],real:[5,16,36,37,38,40,50],realiti:[16,44],realiz:41,realli:[5,16,36,38,40,41,42,44,46,50],rearm:39,reason:[6,16,31,36,37,40,41,42,43,45,46,50],rebuild:[28,42,43],recal:[8,13,27,38,39,40,43],receiv:[8,16,26,27,35,37,38,39,40,41,42,43,44,45,46,50],receiving_entri:38,receiving_receiv:38,recent:[38,40],reciev:[],recip:[33,36,39,43],recipi:50,reckless:36,recogn:[16,39],recommend:[5,36,37,40,42,43,45,46,48],reconnect:37,reconsid:[38,49],reconstruct:5,record:50,rectang:[],rectangl:[16,40,41,42,44,46,50],rectangular:41,recurs:[16,38,39,41,50],red:[10,40,41,42,50],red_light_off:10,red_light_on:10,redefinit:36,redesign:38,redraw:[38,42],reduc:[8,16,40,43,50],reduct:[],redund:[16,50],reef:[],ref:[],refact:8,refactor:[16,36,38,40,41],refer:[7,9,16,18,19,20,21,22,23,27,30,35,36,37,38,39,40,41,42,43,45,46,47,48,50],referenc:[8,9,15,16,36,42,43,50],refil:16,reflect:[8,16,26,33,36,38,39,42,46],reflection_sign:[26,42,43],refocu:16,reform:41,refrain:[],refresh:50,regain:36,regard:[36,38,39,50],region:[8,16,38,41,50],regist:[37,42],register_live_spy_callback:[37,42],register_live_trace_callback:[37,42],register_par:[42,49],register_signal_callback:[42,49],registr:[42,49],registri:0,regress:[16,29,42,43,50],regroup:16,regular:42,reject:36,rejoic:50,rejoin:50,rel:[8,50],relai:[40,41,50],relat:[5,8,9,16,37,38,39,41,42,49,50],relationship:[8,9,41,42],relax:[38,50],releas:[5,8,36,38,41,48,50],relentlessli:[],relev:38,reli:[16,38,50],reliabl:50,reliev:[13,42],religi:5,relinquish:50,reload:16,reluct:[41,43],remain:[16,38,41,46,50],remark:[5,16],remedi:[],rememb:[5,16,38,39,41,42,44,46,50],remidi:8,remind:[8,16,40,42,45,50],reminder_pattern_needed_1:38,reminder_pattern_needed_2:38,remov:[16,29,37,38,40,41,42,43,48,49,50],renam:49,render:[16,41],renderexplorewidget:[],rendit:39,reorgan:16,repeat:[8,11,38,40,41,42,46,49,50],repeatedli:39,repetit:[16,50],replac:[15,16,37,42,43,45,50],replic:[15,42,43],repo:2,report:[38,42,50],repost:[13,42],repres:[8,9,15,16,38,39,41,42,43,46,50],represent:41,reproduc:[30,48,50],request:[0,38,40,42,50],request_city_detail:40,request_details_for_c:40,requestdetailsforcitypayload:40,requir:[6,9,16,30,35,36,38,39,40,41,42,45,46,48,49,50],reset:[41,42],resetchart:46,resettact:16,resettl:[],resili:40,resist:16,resolut:16,resolv:40,resourc:[5,16,40],respect:[16,50],respond:[8,16,17,35,39,42,43,46,49,50],respons:[16,38,42,46,50],rest:[16,37,38,39,41,42,46],restart:0,restor:46,restructuredtext:50,resubscrib:37,result:[16,17,28,29,30,36,37,38,39,40,41,42,43,46,48,49,50],resulting_funct:49,resurrect:46,ret_sup:6,ret_super_sub:6,ret_zz:6,retir:5,retreat:[16,17],retreat_ready_war:16,retreat_ready_war_cri:[16,17],retreat_war_cri:[16,17],retri:41,retriev:[],retry_after_network_error:40,return_st:[38,42,50],return_statu:[10,16,17,25,26,35,38,40,41,42,43,44,46,49,50],returncod:6,returnstatussourc:1,reus:38,reusabl:38,reveal:[5,16,44],rever:50,revis:45,revolt:[],rewind:46,rich:[5,42,50],richard:47,richest:5,richli:[],rid:[36,40,50],ride:[16,35,40],ridg:[],ridget:[],rig:[],right:[5,8,16,37,38,40,41,44,49,50],right_wal:[],rightfulli:[],rigid:[38,41],rigor:[5,16,50],ring:[8,27,38,42,43,50],risk:16,ritual:50,rlock:48,robot:[36,40],robust:[16,36,37],roll:[41,42],roman:[],ronach:8,room:[27,41,42,43],root:[],rosetta:50,rotat:[16,38],rough:[40,50],roughli:[5,50],round:[40,41,42,50],rout:[16,37,45],routin:[9,38,49],routing_kei:37,row:49,row_to_check:[],rpc:45,rst:[],rtc:[0,5,8,9,27,38,41,42,43,46,50],rubbl:[],rubi:50,rudimentari:[],rule:[5,8,16,30,35,36,40,42,46,48,50],rule_30:[],rule_30_black_walls_200_gener:[],rule_30_white_walls_100_generations_width_30:[],rule_30_white_walls_200_gener:[],rulebook:[],ruler:[],run:[0,4,5,8,9,10,15,16,24,25,27,28,29,30,35,36,37,38,39,40,41,42,43,45,46,48,49,50],run_anim:[],run_ev:0,runtim:42,rush:[],ruthlessli:44,rx_routing_kei:16,s11:[4,44],s11_state:44,s1_state:44,s211:4,s21:[4,9,44],s21_state:[25,42,44],s2_state:[25,42,44],s_state:[25,42,44],safe:[1,5,7,16,30,38,41,44,50],safeti:[16,42,48],sai:[5,16,38,39,40,41,42,46,49,50],said:[36,38,42,46,50],sake:42,salari:5,salt:39,same:[0,4,5,6,7,9,11,12,16,26,29,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],samek:[5,8,9,16,36,38,39,41,42,44,49,50],sampl:[38,40,50],sandwich:[],saskatoon:40,satisfact:[44,50],satisfi:50,saturn:5,sausag:40,save:[11,16,38,39,42,43,45],savefig:[],saw:[16,36,40,42,46],scaffold:[],scalabl:45,scale:[36,38],scan:[16,36,40,41,46],scare:[16,17],scari:48,scenario:50,scene:50,scheme:[16,38,42],scienc:[38,41],scientif:[44,47],scimitar:[16,17],scipi:[],scope:37,score:5,scotti:45,scrambl:50,scratch:16,screen:[4,16,28,37,40,42,43],screw:[30,48],scribbl:[8,16,17,25,35,38,41,44,46,50],script:[37,45,50],scroll:50,sculpt:16,search:[8,9,12,33,38,39,41,42,46,49,50],search_for_super_sign:[26,27,28,35,37,38,39,41,42,43,44,46,49,50],season:16,sec:[16,17],second:[8,12,16,17,31,36,38,39,40,41,42,43,44,49,50],secondari:8,secondli:[],secret:[16,45,50],secretli:38,section:[4,7,16,36,39,40,41,42,45,46,49,50],secur:[16,45],see:[0,4,5,6,8,14,15,16,25,26,30,31,35,36,37,38,39,40,41,43,45,46,48,49,50],seed:38,seek:44,seem:[5,16,30,36,37,38,42,46,48,49,50],seemingli:48,seen:[6,8,16,38,40,41,42,45,46,48,50],segment:36,select:[15,42,43,50],self:[6,9,10,16,17,37,38,39,40,41,42,45,48,50],selfpayingtoasteroven:10,sell:[],semant:[36,38,39,41],semaphor:5,semblanc:16,send:[4,6,8,15,16,36,38,39,40,41,42,43,44,45,46,49,50],send_broadcast:42,senior:[16,17],senior_advance_war_cri:[16,17],senior_retreat_war_cri:16,senior_skirmish_war_cri:[16,17],sens:[16,37,39,40,41,42,43,44,45,46,50],senseless:39,sensibl:[16,36,42],sensit:[],sensor:[16,38],sent:[8,16,35,37,38,39,40,41,42,46,50],sentenc:[16,41,50],seoc:[],separ:[5,16,37,38,39,40,41,42,50],seper:8,sequenc:[8,9,15,16,31,35,37,38,40,43,44,50],sequence_diagram:41,seri:[36,46],serial:6,seriou:[5,50],serious:5,serv:[16,40,41,42,50],server:[37,38,40,45,50],servic:[5,8,40],session:[28,42,43],set:[0,8,9,11,16,36,38,39,40,41,42,48,50],set_arrai:[],set_aspect:[],set_ticks_posit:[],set_titl:[],set_trac:[28,42,43],set_xticklabel:[],set_yticklabel:[],setter:[],settl:[8,9,12,16,38,41,42,46,50],setup:[16,40,45],seventi:[],sever:43,shadow:9,shake:50,shallow:50,shalt:46,shape:49,share:[5,8,9,16,26,30,35,36,38,39,40,41,42,43,48,50],she2:41,she:[41,50],sheet:16,shelf:38,shell:[16,41,45],shelv:38,shift:[27,42,43,50],shine:38,ship:[16,50],shoot:[16,41,49,50],shop:50,shortcode1:[],shortcode2:[],shorten:[],shorter:16,shorthand:[16,41,44,50],shortli:[38,41,42,45],shot:[8,11,12,16,17,38],should:[5,6,8,11,12,16,29,35,36,37,38,39,40,41,42,43,45,46,49,50],shoulder:[36,50],shouldn:[29,41,42,43,48,50],shout:16,show:[0,8,16,35,36,37,38,39,40,41,42,45,46,48,49,50],shown:[4,5,50],shrink:41,shut:[37,41,46,50],shutdown:43,side:[5,16,41,42,50],sight:[],signal:[0,1,4,8,9,10,11,12,13,16,17,25,26,27,31,35,37,38,39,40,41,44,46,49,50],signal_callback:[8,49],signal_nam:[0,6,26,40,41,42,43],signal_numb:[26,40,42,43],signal_that_is_def:[13,42],signalsourc:[1,26,42,43],signatur:[37,39,42,49,50],signifi:41,signific:[16,30,48],significantli:[5,36,37],silo:[],similar:[16,36,38,41,42,49,50],similarli:38,simpl:[15,16,18,27,30,36,37,38,40,41,42,43,45,47,48,49],simple_fsm_2:41,simple_state_10:42,simple_state_11:42,simple_state_12:42,simple_state_13:42,simple_state_14:42,simple_state_15:42,simple_state_3:42,simple_state_5:42,simple_state_6:42,simple_state_7:42,simple_state_8:42,simple_state_9:42,simpleacyncexampl:[],simpleasyncexampl:[],simpler:[16,42],simpli:[5,30,38,41],simplic:[15,38,42,43],simplif:16,simplifi:[5,38,40,41,50],simul:[38,50],sinc:[5,6,9,12,15,16,27,35,36,37,38,39,41,42,43,44,45,46,47,48,50],singl:[7,16,36,38,39,41,42,50],singleton:[0,8,26,42,43],singular:[],sissi:[],sisyphean:[],sit:[8,16,42,50],site:[9,45],situat:[13,16,25,30,38,42,44,48,50],sixti:16,size:[38,40,50],sketch:[8,16,29,36,40,41,42,43],skill:16,skip:[16,37,38,42,46],skirmish:[16,17],skirmish_ammunition_low:[16,17],skirmish_entri:[16,17],skirmish_exit:[16,17],skirmish_officer_lur:[16,17],skirmish_other_squirmish_war_cri:[16,17],skirmish_retreat_ready_war_cri:[16,17],skirmish_second:[16,17],skirmish_senior_squirmish_war_cri:[16,17],skirmish_war_cri:[16,17],sky:50,slai:16,slam:38,slaughter:16,slave:42,sleep:[10,16,35,37,38,39,40,41,42,44,46,48,49,50],slide:39,slight:16,slightli:[16,41,42,50],slip:50,slot:[38,48],slow:[16,42,50],slower:8,slowest_tim:38,slowli:[16,50],small:[15,16,36,38,39,42,43,44,50],smaller:[16,41,42],smallest:[41,43],smart:[],smarter:16,smash:[],smear:50,smell:50,smile:50,smurf:16,snail:[],snap:[16,50],snare:16,snippet:[16,39,41,50],snoop:16,snoop_kei:16,snoop_scribbl:16,snoop_spy_encryption_kei:16,snoop_trace_encryption_kei:16,snow:40,social:47,societi:50,sock_dgram:37,socket:[37,42],softwar:[5,8,16,35,36,38,40,42,45,49,50],soil:[],soldier:16,solid:41,solips:50,solipsist:50,solo:[],solut:[36,38],solv:[8,30,36,37,38,40,41,42,48,49],solver:[],some:[5,8,12,15,26,30,35,36,38,39,40,41,42,43,44,46,47,48,49,50],some_event_the_system_has_never_seen:[],some_example_st:[26,42,43],some_st:[41,42,50],some_state_funct:50,some_state_to_prove_this_work:50,somebodi:39,somehow:[16,50],someon:[16,30,35,38,39,40,41,42,43,48,50],someth:[0,5,8,16,26,29,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],something_els:42,sometim:[9,16,17,30,41,48,50],somewai:[],somewhat:[36,37],somewher:[16,40,50],soon:[16,37,38],sorri:5,sort:[16,35,38,39,41,42],sound:[39,50],sourc:[2,8,9,15,16,36,39,41,43,44,45,50],source_st:41,space:[9,16,36,38,39,42,50],span:[37,50],spare:42,sparingli:[],spawn:50,speak:[8,12,39,41,42],spec:[18,19,20,21,22,23,38,41,50],special:[4,16,35,38,39,41,46,50],specialist:41,specif:[15,16,27,28,29,36,38,39,41,43,44,46,48],specifi:[0,38,41,42,50],specifici:[],speed:[5,16,36,38,40,42],spell:49,spend:[5,16,36,41,50],spent:[5,16,36,41],sphere:38,spike:50,spinkler:[],spirit:[42,50],spit:37,split:[16,46,50],spoil:16,spooki:[],sporat:38,spot:[8,16,27,42,43,50],sprai:[],spread:[16,36],spreadsheet:16,sprei:[5,35],sprinker:[],sprinkler:36,sprinkler_heart_beat_sec:40,sprinkler_high_level:[],sprinkler_off:40,sprinkler_off_entry_sign:40,sprinkler_off_init_sign:40,sprinkler_on:40,sprinkler_on_done_wat:40,sprinkler_on_entry_sign:40,sprinkler_on_exit_sign:40,sprinkli:[],spruce:37,spy:[0,4,8,16,24,25,27,28,35,38,39,41,44,46,49,50],spy_callback:[37,42],spy_ful:[39,46],spy_lin:50,spy_liv:37,spy_of_trac:50,spy_on:[4,10,11,12,14,16,17,25,38,39,41,42,43,44,46,49,50],spy_on_buzz:50,spy_on_heater_off:50,spy_on_heater_on:50,spy_on_light_off:50,spy_on_light_on:50,spy_or_trac:50,spy_queue_nam:37,spy_result:37,squar:[31,38,42,43,44],squirrel:46,squish:[],src:[],ssaw:[],ssh:45,ssl:[],sssub:[],stabil:50,stabl:50,stack:[37,48],stadium:[],staff:5,stage:[13,16,38,42,50],stai:[16,38,42,50],stair:50,staircas:50,stamp:[31,38,42,43,50],stand:[42,46,49,50],standard:[15,34,36,37,41,42,43],star:[38,41,50],stare:[],start:[0,8,9,10,16,17,27,28,30,31,33,35,36,37,38,39,41,43,44,46,48,49,50],start_at:[0,9,10,15,16,17,29,31,35,37,38,39,40,41,42,43,44,46,49,50],start_consum:37,start_exampl:42,start_thread_if_not_run:0,start_tim:50,startchart:[13,42],starting_st:38,starting_state_funct:9,startup:50,starvat:5,stash:[16,17],statchart:8,statchmachin:50,state:[0,4,5,6,8,9,10,11,12,13,14,15,16,17,25,27,30,31,35,36,37,38,39,40,46,48,50],state_at:[],state_chart_object:[],state_fn:[14,42,43],state_method_nam:42,state_method_templ:[8,42,49],state_nam:[0,14,16,17,41,42,43,50],state_recipe_15:[],state_return:6,state_to_transition_to:42,statecchart:[],statechart:[0,4,5,6,7,8,9,10,12,14,15,16,24,25,29,30,36,38,39,40,43,44,46,48,50],statechart_object:[],statehandl:42,stateless:42,statemachin:[4,24,37,41,42,50],statement:[4,16,42,46,48,50],statemethod:[14,42,43],staticmethod:[37,40,41,42,50],station:40,statocol:40,statu:[10,11,12,16,17,25,26,35,37,38,39,40,41,42,43,44,46,49,50],steadi:38,steam:38,stencil:36,step:[8,9,16,38,39,43,44,45,50],stephen:[],stick:[16,50],still:[0,5,16,36,38,39,41,42,44,49,50],stimul:[8,46],stimulu:38,stitch:[],stochast:38,stock:[],stone:50,stop:[0,8,16,17,37,38,39,40,41,46,50],stop_active_object:0,stop_consum:37,stop_fabr:[],stopper:48,store:[5,37,38,39,40,42,50],stori:[5,15,16,28,36,39,41,42,43,46],str:[16,17,26,38,40,41,42,43,50],straight:[30,36,41,42,48],straightforward:[37,38,45],strand:16,strang:[16,39,42,44,49,50],strateg:16,strategi:[5,16,30,37,39,42,48],straw:[],stream:[4,6,16,37,42,50],stretch:[],strftime:[38,42,50],strike:38,string:[6,8,9,14,26,29,37,38,41,42,43,49,50],strip:[16,29,42,43,50],strip_trac:37,stripped_spec:[],stripped_target:[16,29,42,43,50],stripped_trace_result:[16,29,42,43,50],stroke:16,strong:[16,36],strongli:[5,38],structur:[1,8,16,35,36,38,39,40,42,44,45,46,49,50],struggl:39,stub:[],studder:[],studdler:[],studi:[16,50],studio:[],stuff:[41,42,50],stupid:16,stupidli:16,stutter:36,style:[8,42,50],sub:[0,30,37,42,45,48,50],sub_row_to_check:[],subclass:[6,38,41,50],subclassed_ao1:41,subclassed_ao:41,subdesign:42,subject:[],suboptim:38,subordin:16,subplot:[],subscrib:[0,5,8,16,35,36,37,40,45],subscribing_ao:42,subscript:[0,8,16,40,41,42],subservi:50,subset:[5,8,16],substat:[8,9,16,38,41,42],subsubclassed_ao2:41,subsystem:50,subtl:[30,38,48],subvers:50,succe:45,succeed:37,success:[5,38],successfulli:16,suck:16,suddenli:36,sudo:45,sued:[],suffici:16,suffix:[],suggest:[40,42],suicid:[],suit:50,sum:16,summar:[37,43,46],summari:46,summer:40,summer_to_dai:40,summer_to_night:40,summer_to_summ:40,summer_to_wint:40,sun:[],sunk:41,sunni:[],sunris:40,sunset:40,superclass:42,superior:16,supernatur:50,superst:[8,38,41,50],suppli:16,support:[0,9,15,36,37,38,41,42,43,45,50],suppos:[15,16,31,38,42,43,44,48,49,50],sure:[16,17,37,38,40,41,42,49,50],surpris:[38,47,49,50],surround:[5,16],surviv:16,suspens:50,sustain:16,svg:[41,42],swap:5,swarm:16,swell:[],swing:[16,38],symmetr:16,synanoum:[],synchron:[16,36,38,41,42],synonym:[8,41],syntact:[16,38,48],syntax:[26,36,38,39,40,42,43,45,48,49,50],synthes:[],sys:40,system:[5,6,8,9,12,15,16,27,28,30,35,36,38,39,40,41,43,45,46,48,49,50],t_question:44,tabl:[],tabular:[],tack:[],tackl:40,tactic:17,tag:50,tail:[27,38,42,43,46],taint:41,take:[0,5,8,16,36,37,38,39,41,42,44,46,50],takeawai:[],taken:[8,16,36,42],taleb:[35,44],talk:[5,16,36,38,39,41,42,43,45,50],tar:5,tara:50,target:[8,9,12,16,28,29,36,38,41,43,44,48,50],target_st:41,targetandtolerancespec:50,tart_at:[15,42,43],task:[0,5,16,30,42,46,50],task_ev:0,tatechart:[],taught:5,taxat:16,tazor:[15,28,29,31,39,42,43],tazor_oper:[28,39,42,43],tc1:49,tc2:49,tc2_s1:[],tc2_s2:[],tc2_s3:[],teach:5,team:[16,35,36,37,41,43],teammat:[16,43],tear:50,technic:[5,41,42,44,50],techniqu:[0,8,16,37,38,41,42,48,50],technlog:[],technolog:[5,36,37,50],tediou:50,tell:[5,9,15,16,28,36,38,39,40,41,42,43,45,46,50],tem:[],temp:[9,10,11,12,16,17,25,38,39,40,41,42,44,46,48,49,50],temp_max:40,temp_min:40,temperatur:[8,38,40,50],templat:[8,41,42,45],tempor:36,temporari:[6,30,40,42,43,48,50],tempt:[16,50],ten:[16,40,45],tend:[41,42],tension:50,term:[8,27,36,40,41,42,43,50],termin:[4,15,27,37,38,39,42,43,49,50],terminolog:37,terrac:50,terrain:16,terribl:16,test:[0,5,9,10,15,16,28,29,30,33,34,36,37,38,40,44,45,48],test_baking_buzz_one_shot_tim:50,test_buzz_ev:50,test_buzz_tim:50,test_toaster_buzz_one_shot_tim:50,test_typ:50,testabl:50,text:[5,8,15,41,42,43],textil:[],th1:48,th2:48,than:[5,8,10,15,16,17,24,30,35,37,38,39,40,41,43,48,49,50],thankfulli:[16,50],thei:[4,5,8,9,12,15,16,17,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],theirs:[16,50],them:[5,6,8,9,11,12,16,17,35,36,37,38,39,40,41,42,44,45,46,49,50],theme:[],themselv:[8,16,17,36,37,41,42,50],thenc_1:[],theo:50,theoret:[],theori:[16,36,40,41,42,44,47],thepihut:[],therebi:[8,16,37],therefor:[16,39],thi:[0,2,4,5,6,8,9,10,11,12,13,14,15,16,17,26,27,28,29,30,31,35,37,38,39,40,41,42,43,44,45,46,48,49,50],thickest:[],thiel:50,thin:[],thing:[5,6,8,9,13,15,16,28,36,37,38,39,40,41,42,43,44,45,48,49,50],thing_subscribing_ao_cares_about:42,think:[12,16,26,36,37,38,39,41,42,43,44,45,46,48,50],thinner:[],thinnest:[],third:[16,38],thirti:[],this_dir:40,thoma:41,those:[8,16,35,39,41,49,50],thou:46,though:[8,12,16,36,39,41,42,45,46,49,50],thought:[16,17,36,38,42,50],thousand:[],thr2:48,thread:[0,1,4,5,7,8,10,16,30,35,36,37,38,39,40,41,44,46,49,50],thread_method_1:48,thread_method_2:48,thread_race_attr_1:48,thread_runner_fifo:0,thread_runner_lifo:0,thread_safe_attr_1:48,thread_safe_attr_2:[],thread_safe_attribut:48,thread_safe_attributes_2:48,thread_safe_attributes_3_unsaf:48,thread_safe_queu:[],thread_stopp:48,threadev:48,threadkil:48,threadsaf:[],threadsafeattribut:[30,42,48],threadsafeattributesinactiveobject:[],thredo:50,three:[16,36,38,39,40,41,42,45,46,49,50],three_puls:[11,42],threshold:38,throb:50,throe:8,through:[5,6,8,9,15,16,29,30,36,37,38,39,40,43,44,45,46,48,49,50],throughput:16,thrown:43,tick:[16,17],ticket:[],tie:[16,38,39,42,50],tied:[8,16,44],ties:[],tight:[36,50],tight_layout:[],tighten:44,tightli:[28,41,42,43,50],till:36,timat:8,time:[0,4,5,8,10,11,12,16,17,29,30,35,36,37,38,39,40,41,43,44,46,48,49],time_1:50,time_1_str:50,time_2:50,time_2_str:50,time_compress:[16,17],time_differ:50,time_in_sec:50,time_in_second:[16,17],time_keep:9,time_out:38,timeout:37,timeout_callback:37,timer:[37,40,50],times_in_inn:42,timeseri:[],timestamp:[29,42,43,46,50],timestamp_str:50,timezon:40,tini:[5,42,44,50],tip:46,tissu:[],titl:[5,9,39,44,50],to_b1:42,to_cod:[8,16,42,49],to_dai:40,to_method:[16,17,35,37,38,40,41,42,49],to_night:40,to_summ:40,to_tim:[16,17],to_weather_payload:40,to_wint:40,toast:[10,38,50],toast_tim:50,toast_time_in_sec:50,toaster:[10,38,41],toaster_142x5:[],toaster_:10,toaster_baking_to_toast_spec:[],toaster_off_to_baking_trace_spec:[],toaster_oven:41,toaster_oven_1:50,toaster_oven_2:50,toasteroven:[38,41,50],toasterovenmock:50,toasting_buzz_test_spec:50,toasting_entri:38,toasting_time_m:50,toateroven:[41,50],todai:16,togeth:[15,16,30,36,40,41,42,43,47,48,50],toggl:50,told:50,toler:[16,50],toleranc:50,tolern:50,tolernance_in_m:50,tome:36,tonsil:50,too:[0,8,9,15,16,36,37,38,39,40,41,42,43,44,49,50],too_cold:41,too_hot:41,took:[16,35,36,46,50],tool:[5,8,16,35,36,37,41,42,43,45,50],top:[0,7,8,9,10,15,16,17,29,31,34,35,36,37,38,39,40,41,42,43,44,45,46,47,49,50],top_bound:50,topic:[16,45],topolog:[9,35,36,38,39,41,42,49,50],topology_a:9,topology_h:9,toronto:40,total:44,totalitarian:38,touch:[5,42,50],tough:48,toward:[9,16,38,50],tpath:9,trace:[0,4,8,15,16,24,28,29,31,35,38,39,40,41,46,48,50],trace_callback:[37,42],trace_l:37,trace_lin:50,trace_queue_nam:37,trace_result:37,trace_target:50,trace_through_all_st:50,trace_without_datetim:42,track:[16,17,37,38,41,42,43,46,50],tracker:[],trade:[38,39,41,42,49,50],tradit:[5,16,36,39,41,50],traffic:16,train:[16,36,42],trajectori:[],tran:[8,9,10,11,12,16,17,25,35,37,38,39,40,41,42,44,46,49,50],tranduc:38,trans_:9,trans_to_c2_s1:[],trans_to_c2_s2:[],trans_to_c2_s3:[],trans_to_fb11:35,trans_to_fb1:35,trans_to_fb:35,trans_to_fc1:[35,42,49],trans_to_fc2:[35,49],trans_to_fc:[35,42,49],trans_to_tc1:49,trans_to_tc2:49,trans_to_tc:49,transact:43,transduc:[8,16,38],transfer:[38,39,42,44],transform:[],transit:[0,4,8,9,11,12,16,17,31,35,39,40,41,43,44,46,49,50],transitori:50,translat:[36,38,43],transmit:[16,37,45],transpar:[],transpir:50,travel:[],travers:39,treat:[9,41,50],tremend:16,trend:36,trends_nrtr:[],tri:[8,16,36,38,42,48,49,50],trial:38,triangl:[],tribe:39,trick:16,tricki:41,trickl:42,trigger:[8,9,16,17,38,39,40,41,44,49,50],trigger_pul:39,trip:16,trivial:[16,35,41,42,50],troop:16,troubl:[5,16,39,41,49],troubleshoot:[4,36],troublesom:5,truck:38,truli:[16,41],trust:[16,42,50],truth:16,tube:[],tunabl:[38,50],tune:[16,38],tupl:[40,41,42],turbin:38,turn:[5,6,8,10,15,16,29,35,36,38,39,40,41,42,43,44,45,46,48,49,50],turn_off_sprinkl:40,turn_on_sprinkl:40,tutori:[33,36,37,45],twain:16,tweak:16,tweek:[],twice:[42,50],twist:36,two:[0,4,5,8,13,15,16,30,36,37,38,39,40,41,42,43,44,45,46,48,49,50],twodcellularautomatawithanglediscoveri:[],twodcellularautonomata:[],tx_routing_kei:16,type:[4,6,11,16,31,35,36,38,40,41,42,43,45,46,49,50],typic:[0,16,30,35,36,41,42,48,50],typof:[],u3uc:[16,37],ubuntu:[],ugli:50,ultim:[4,8,39,41,46,50],ultimate_hook_exampl:38,ultisnip:[41,50],uml:[5,8,15,16,35,36,37,38,40,42,43,44,50],umlel:[],umlet:[15,16,36,41,42,43],umletino:42,unawar:42,uncom:[28,42,43],uncomfort:50,undefin:[42,50],under:[5,16,36,41,42,45,50],underl:50,underli:[8,50],underneath:[],understand:[8,9,16,27,30,35,36,38,39,40,41,42,43,44,46,47,48,49,50],understood:36,underworld:50,unexcept:16,unexpect:[16,41,42],unfamiliar:44,unfold:16,unforeseen:16,unfortun:[5,36,41],ungodli:5,unhandl:[6,10,11,12,16,17,25,35,38,39,41,42,44,46,49,50],unhanld:[26,42,43],unifi:41,uniform:38,uniqu:[6,16,31,42,43,49,50],unison:[16,37,38],unit:[5,8,15,17,38,40,42,43,50],univers:[8,16,36,47,50],unives:[],unless:[8,16,42,50],unlik:[5,8,16,39,42,47,48],unlink:16,unload:39,unlock:[30,41,48],unmanag:8,unnecessari:[11,42],unneed:50,unorgan:16,unpredict:38,unprocess:42,unprotect:[5,16],unreason:[],unreli:[],unrespons:50,unseen:6,unstabl:46,unstart:[],unsupport:47,unsuspect:39,untest:50,until:[5,8,9,16,30,37,38,39,40,41,42,46,48,50],unus:50,unusu:16,unwind:[7,8,42,43],upcom:50,updat:[15,16,29,36,42,43,50],update_angl:[],upon:[5,8,13,16,17,26,34,35,38,39,40,41,42,43,46,49,50],upper:[16,41,50],upward:[],url:40,usag:50,use:[0,5,8,11,12,15,16,25,26,27,29,30,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50],used:[0,2,5,6,8,9,10,11,12,15,16,30,31,36,37,38,39,40,41,42,43,44,45,46,48,49,50],useful:[9,11,16,36,37,38,39,41,42,50],useless:50,uselessli:16,user:[0,8,37,38,39,41,42,43,45,46,50],uses:[0,4,6,8,16,36,38,39,40,41,42,45,48,49,50],using:[0,4,5,6,8,9,15,16,27,29,30,31,35,36,37,38,39,40,41,43,45,46,48,49,50],usual:50,utf:40,util:[15,42,43],uuid5:0,uuid:0,vagu:[],vain:5,valid:9,valour:16,valu:[6,8,16,26,30,38,42,43,48,50],valuabl:[],valv:40,vancouv:40,vantag:[16,50],variabl:[5,8,9,16,29,30,35,38,39,41,42,43,45,46,48,50],varient:[],varieti:37,variou:[8,16,39,42,46,50],veer:16,veloc:[],vendor:41,vent:42,venv:50,verbiag:[],verbos:[],veri:[0,5,15,16,27,30,31,35,36,38,39,40,41,42,43,44,46,48,49,50],verifi:[36,38,50],vers:43,version:[4,37,40,42,45,49,50],versu:50,vertic:[41,42,50],vestigi:50,via:[38,42,45],viabl:[],victim:39,victori:5,video:[16,42],videoid:[],view:[5,8,16,36,37,38,39,41,42,44,46,47,50],vigil:16,vim:[35,41,42,50],virtual:50,visibl:[40,41,42],visio:[36,43],vision:[16,35,36],visit:42,visual:[35,50],vital:41,vitamin:41,vnc:[],voic:16,voltag:[39,50],voltair:48,volum:36,voodoo:16,vortex:38,wai:[0,5,8,11,13,16,17,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],waist:5,wait:[0,5,10,11,16,17,30,36,37,38,39,40,41,42,44,46,48,50],waitcomplet:46,waiting_to_adv:[16,17],waiting_to_lur:[16,17],wake:[8,38,50],walk:[38,49,50],walker:50,wall_cl:[],wallleftblackrightblack:[],wallleftblackrightwhit:[],wallleftwhiterightblack:[],wallleftwhiterightwhit:[],want:[9,12,13,16,26,27,29,30,36,37,38,39,40,41,42,43,45,46,48,49,50],war:[5,16,17],warbot:16,ward:49,warhors:16,warn:42,wasn:[16,28,38,40,42,43,46,50],wast:[8,16,38,39,41,43,50],watch:[0,5,16,36,37,39,41,42,46,49,50],watch_external_weather_api:[],watch_external_weather_api_entri:[],watch_external_weather_api_weather_report:[],water:[16,17,40],water_time_sec:40,wave:[16,38,40,50],weak:16,weaken:16,weapon:[5,16,35],wear:16,weather:[36,40],weather_dict:40,weather_read:[],weather_report:[],weather_results_dict:40,weather_track:[],weather_work:40,weather_worker_city_detail:40,weather_worker_entry_sign:40,weather_worker_get_weath:40,weather_worker_weath:40,weatheropenapiresult:40,weatherreport:[],weav:16,web:[40,45,50],websit:[40,45],weekend:[],weigh:[5,42],weight:[5,35],weird:42,weirder:42,well:[0,5,6,9,16,36,39,41,42,44,45,49,50],went:[36,45],wenzel:45,were:[0,4,5,8,16,29,36,37,38,39,40,41,42,43,46,48,49,50],weren:[5,16,36,49,50],western:16,what:[5,8,9,14,16,27,28,29,31,35,36,37,38,39,41,44,45,46,47,48,49,50],whatev:[16,36,41,42,44,45,50],whatever_name_you_w:[],when:[4,5,8,9,11,13,15,16,17,27,28,29,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],whenev:38,wher:[],where:[0,5,8,9,13,16,24,30,35,37,38,39,40,41,42,45,46,48,50],wherea:43,wherev:50,whether:49,which:[0,5,6,8,9,13,15,16,26,27,28,29,30,35,36,37,38,39,40,41,42,43,44,45,46,48,49,50],whichev:[38,42],whine:39,whisper:50,white:[10,50],white_light_off:10,white_light_on:10,white_mask:[],who:[5,8,16,36,37,38,39,41,42,43,48,49,50],whoever:[],whole:[5,16,26,37,39,42,43,50],wholli:36,whose:[16,36],why:[15,16,30,35,36,38,40,41,42,43,46,47,48,50],wide:[],widget:41,width:[],wiki:38,wikipedia:50,wild:48,willing:16,wilt:[],win:5,wind:40,window:[16,24,37,50],wipe:[],wire:[16,37,40],withe:[],within:[0,4,5,6,8,9,12,16,17,25,35,36,37,38,39,41,42,43,44,46,48,49,50],withing:[],without:[5,8,15,16,27,36,38,41,42,43,48,49,50],woke:46,wolfram:[],won:[5,11,13,36,38,39,41,42,43,50],wonder:38,word:[5,8,16,36,43,45,50],work2:42,work:[0,4,5,8,9,10,13,14,15,16,29,30,35,36,37,38,39,40,41,43,45,46,47,48,49,50],worker1:42,worker2:42,worker:[5,10,41],workflow:16,world:[5,8,13,16,36,38,41,42,45,46,50],worri:[39,41,42,46,49,50],wors:[5,16],worst:[16,50],worth:[16,36,38,41,49],worthwhil:50,would:[0,5,8,9,11,12,13,15,16,26,27,28,29,30,31,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50],wouldn:[16,36,39,40,41,42,44,49,50],wound:[16,17],wrap:[6,9,14,16,17,37,41,42,43,48,49,50],wrapper:9,wrestl:[45,49],write:[4,5,8,15,16,27,28,30,35,36,37,38,39,40,41,42,43,45,46,48,50],written:[4,5,8,9,16,35,36,37,38,39,41,42,45,48,49,50],wrong:[9,16,30,36,39,48,49],wrote:[5,16,36,37,38,39,40,44,45,49,50],wsl:50,wta_entri:[16,17],wta_exit:[16,17],wtl_entri:[16,17],wtl_exit:[16,17],wtl_second:[16,17],www:41,x15:50,x_px:41,xaxi:[],xml:8,xor:[],y_px:41,yaml:8,yaxi:[],year:[5,36],yell:[16,17,50],yellow:[],yes:[16,41,50],yet:[5,8,12,15,16,38,39,40,41,42,43,44,48,49,50],yield:38,yml:[8,45],you:[0,2,4,5,6,8,9,11,12,13,14,15,16,25,26,27,28,29,30,31,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50],your:[0,4,5,6,8,9,11,12,13,14,15,16,25,26,27,28,29,30,31,35,36,37,38,39,40,41,44,45,46,47,48,49,50],your_parent_state_method:42,your_signal_nam:42,your_state_method_nam:42,yourself:[8,16,38,39,41,42,47,49],youtub:[41,42],yse:[],z_px:41,z_pz:41,zap:39,zero:[5,16,18,33,36,38,40],zero_to_on:[7,18,19,20,21,22,23,41,50],zeromq:50,zip:[16,29,42,43,50],zoologi:5,zoom:42,zuvk:[]},titles:["Active Object","Architecture","Cellular Automata","City Sprinkler","Comprehensive","Concurrency: the Good Parts","Events","Examples","Glossary","Hsm","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","Mongol Horse Archer","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","<no title>","Python Statecharts","Installation","Interacting Statecharts (Same Machine)","Introduction","Spy and Trace Across a Network","Patterns","Simple Posting Example","Quick Start","Diagrams","Recipes","Reflection","Hacking to Learn","Setting Up RabbitMQ","Active Object Example","Testing","Thread Safe Attributes","Using and Unwinding a Factory","Tutorial: Zero To One"],titleterms:{"abstract":[42,50],"catch":42,"class":[37,41,42,49],"final":41,"function":[37,42,44],"import":[37,41,44],Adding:42,And:42,For:16,Going:42,Has:42,One:[42,50],The:[16,37,41,43],Using:[42,43,49],abil:37,about:[36,41,42],across:37,activ:[0,42,46],activeobject:42,activeojbect:[],add:[37,42,44],analog:[],anoth:42,ansibl:45,answer:44,anyth:44,approach:49,archer:16,architectur:1,around:40,arrow:41,attach:[16,41,42],attribut:[42,48],augment:[],augmentng:42,automata:2,balkan:[],basic:[45,50],behavior:[42,43],better:44,between:42,boiler:[37,42],build:[16,42],callback:[37,49],can:37,cancel:42,canva:[],capabilit:[],capabl:42,cellular:2,challeng:44,chart:43,citi:3,citydetail:[],cityweath:40,close:37,code:[37,42,44,50],colloqui:[],colour:41,common:44,commun:42,compon:38,comprehens:[4,42],concurr:5,condit:42,connect:37,construct:41,consum:37,content:42,context:[16,36,37,41],count:37,creat:[37,42,49],current:42,deceit:16,decrypt:37,deep:41,defer:[38,42],demonstr:42,describ:42,descript:43,design:[16,37,43,50],destroi:42,detail:[16,41,43],determin:42,diagram:[41,42],docstr:37,document:36,doe:[],dot:41,draw:[37,41,42],dynam:[],els:41,embed:[],enter:[],entri:42,entropi:[],escal:[],event:[6,37,38,41,42,44,49,50],exampl:[7,16,35,37,39,46,49,50],exit:42,experienc:[],explain:43,extend:41,extern:42,extrem:43,fabric:0,factori:[42,49],fall:41,feder:41,feedback:42,fifo:42,figur:40,first:[16,44],flat:42,foreignhsm:37,frame:44,from:[42,43],game:[],gener:[],get:37,glossari:8,good:5,guard:[42,44],hack:44,handl:42,handler:42,hardwar:50,have:[37,42,43],heartbeat:42,hiearchi:44,high:[41,43],highlevel:[],highlight:[],hint:[],histor:16,histori:[36,38,41,50],hook:[38,42,50],hors:16,horseman:16,how:43,hsm:[9,37,42],hypothesi:44,icon:41,idea:[],indic:33,inform:[37,40,42],inherit:41,init:44,initi:42,insid:42,instal:[34,41,45],instrument:[4,42],interact:35,intern:44,introduct:36,invent:42,iter:50,its:[16,37],learn:[44,45],level:[41,43],librari:37,lifo:42,link:37,linux:45,live:[42,43],live_spi:42,log:37,logger:42,machin:[35,42],make:[37,42,44],mechan:[],medium:41,mesh:16,messag:[37,45],method:[42,49],mind:16,minim:42,miro:[41,42],mistak:44,model:16,modul:6,mongol:16,more:42,most:41,multi:[42,50],multichart:38,multipl:42,multishot:42,name:42,need:[],network:[16,37,40,45],newbi:[],noth:[],number:[],object:[0,37,42,46],off:37,one:[42,50],onedcellularautomata:[],openweathermapcitydetail:40,organ:[],orthogon:38,other:[42,43,44],our:[16,37,44],out:40,output:[37,43],oven:50,over:[],overload:42,overview:16,own:42,pai:[],parent:42,part:5,partial:44,pass:[40,42],pattern:[38,45],payload:[41,42,50],pend:38,phenomenon:[],pictur:44,plate:[37,42],point:[41,42],post:[39,42],processor:41,produc:37,program:37,proof:50,provid:[],pub:41,publish:[41,42],python:[33,42],question:[44,50],quick:40,rabbitmq:[37,45],race:38,random:[],react:37,recal:42,recip:42,refactor:[],reflect:43,regist:49,releas:42,remind:38,requir:[37,44],returnstatussourc:6,ride:[],rule30:[],rule:41,run:44,safe:[42,48],same:35,scott:[],scribbl:42,see:[42,44],self:[],send:37,sequenc:[41,42],set:[37,45],setup:50,share:[],shot:[42,50],shutdown:37,signal:[6,42,43],signalsourc:6,simpl:[35,39,50],sketch:[],small:[],softwar:41,some:[16,37],someth:[],sourc:42,specif:[37,42,49,50],sprinkler:[3,40],spy:[37,42,43],standard:49,start:[40,42],state:[41,42,43,44,49],statechart:[33,35,37,41,42,49],statemachin:[],stop:42,stori:50,structur:41,sub:41,subclass:42,subscrib:[41,42],subscript:[],subsect:[],subsubsection_titl:[],summari:49,system:42,tabl:33,tactic:16,target:42,technic:16,templat:49,termin:41,test:[42,43,47,50],than:42,thi:36,thought:43,thread:[42,48],through:[41,42],time:[42,50],titl:[],toaster:50,trace:[37,42,43],transit:[38,42],translat:50,turn:37,tutori:50,twodcellularautomata:[],ultim:38,uml:41,umlet:[],unit:16,unwind:49,use:42,using:42,viabl:42,view:43,visual:[],volk:[],wall:[],warn:41,what:[40,42,43],when:[],why:49,window:45,work:[42,44],worker:42,write:49,you:42,your:[42,43],zero:50}})
\ No newline at end of file
diff --git a/docs/thread_safe_attributes.html b/docs/thread_safe_attributes.html
index 8ed9825..c2fa5e5 100644
--- a/docs/thread_safe_attributes.html
+++ b/docs/thread_safe_attributes.html
@@ -17,8 +17,8 @@
-
-
+
+
@@ -35,9 +35,13 @@
If you use a statechart, your program is multi-threaded.
+
If you use a miros statechart, your program is multi-threaded.
Sometimes, you will want to access an attribute of your statechart from another
thread, like the main part of your program. When you do this, you are trying to
access memory that could be changed in one thread while it is being read in by
@@ -99,7 +103,7 @@
non-atomic “+=”, “-=” … “//=” statements using thread-safe attributes were
also wrapped within locks. For more complex situations, the
thread-safety features provided by the ThreadSafeAttributes class can be
-used get to get the thread lock explicitly.
+used to get the thread lock explicitly.
I will introduce these ideas gradually through a set of examples. Let’s
begin by looking at four interacting threads (possible race conditions are
highlighted):
The lock can be obtained by calling _,_lock=<thread_safe_attribute>.
-
This is a little nasty piece of metaprogramming that could baffle a beginner or
-anyone who looks at the thread safe attribute. Most of the time your thread
-safe attribute acts as an attribute, but other times it acts as an iterable,
-what is going on? It only acts as an interable when proceeded by _,_lock.
-If you use this technique in one of your threads, you must use it in all of your
-threads.
-
Once again I recommend against performing calculations directly on your shared
-attributes. Instead, copy their variable into a temp, perform a calculation
-then assign the results into them.
+
This nasty little piece of metaprogramming could baffle a beginner or anyone who
+looks at the thread safe attribute: Most of the time your thread-safe attribute
+acts as an attribute, but other times it acts as an iterable, what is going on?
+It only acts as an iterable when proceeded by _,_lock. If you use this
+technique in one of your threads, you must also explicitly get the lock in all
+other threads that share the attribute.
+
This lock-access feature was added for difficult situations, where the client
+code absolutely needs the lock, maybe for advanced database calls or that kind
+of thing.
+
I recommend against explicitely getting a lock and performing calculations
+directly on your shared attributes.
+
Instead, copy their contents into a local variable (automatically locked) ,
+perform a calculation using local variables, then assign the results back into
+the shared attribute (automatically locked).
+
In our example, we don’t need to use shared attribute at all, so we shouldn’t.
+The example was arbitrary, a better way to perform the calculation can be seen
+in the following code listing. If we needed to place the 0.3 back into the
+shared-attribute, we can do that, but we keep the shared-attribute out of our
+equation. The equation will use non-shared, thread-safe, local variables which
+are placed on the stack during a thread’s context switch.
+
# code which doesn't require an explicit lock
+temp=0.30
+b=temp*math.cos(0.45)+3*temp**1.2
+print("thr2: ",b)
+# this code will be implicitly locked by ThreadSafeAttributes
+self.gl1.a=temp
+
+
Note
The ThreadSafeAttributes feature actually reads the last line of code you
@@ -769,8 +792,8 @@