A timer specially built for repetitive, timed routines---like stretching. Specify a list of stretches and their variations concisely, then hit play and you'll run through each of them.
Routines can be given in two languages: a high-level specification called the program format and a lower-level, explicit specification called the plan format.
At its core, a routine is just a list of actions, i.e., things to do: a stretch (or some other activity with som properties), a pause to rest or get ready for the next stretch, or an announcement of some kind (e.g., what the next stretch is). A plan is just a list of these entries. Each entry is either a named thing with some properties to be done for some duration, a pause for some duration, or an announcement.
An expression in the program format compiles down to a plan, which is a series of entries. The plan format is a subset of the program format.
The line-oriented, indentation-sensitive program format offers concise specifications: you can "scope" a variation over a large set of entries.
keywords:
pause, vary, in, repeat, shuffle, intersperse, before, after, and, between
BLOCK ::= vary NAME: VALUE(, VALUE)*
BLOCK
| repeat N
BLOCK
| ENTRY
[BLOCK]
| SHUFFLE
BLOCK
| intersperse
BLOCK1
[in|before and in|after and in|before and after and in|around]
BLOCK2
ENTRY ::= NAME DURATION (NAME: VALUE(, VALUE)*)*
[NAME: VALUE(, VALUE)*]
[repeat N]
| pause DURATION
| announce MESSAGE
NAME ::= [^0-9]*
VALUE ::= [^,]*
DURATION ::= [[H:]M:]S
MESSAGE ::= [^\n]*
The compiled plan format is just a list of entries.
PLAN ::= ENTRY
| ENTRY
PLAN
ENTRY ::= NAME DURATION (NAME: VALUE)*
| pause DURATION
| announce MESSAGE
NAME ::= [^0-9]*
VALUE ::= [^,]*
DURATION ::= [[H:]M:]S
MESSAGE ::= [^\n]*
Key/value pairs are additive--we just tack them on.