generator_annotations

auto-webclient grammar version worf.13

  1. Dashboard
    1. Widget: integer
    2. Widget: Progress bar
    3. Widget: Gauge
    4. Widget: Pie Chart
    5. Widget: Bar Chart
    6. Widget: Grouped Bar Chart
    7. Widget: Stacked Bar Chart
    8. Widget: Line Chart
    9. Widget: Area Chart
    10. Widget: Scatter Chart
    11. Widget: Bubble Chart
    12. Widget: Connected Scatter Chart
    13. Widget: Spider Chart
    14. Widget: Radar Chart
    15. Widget: Legend
  2. Widget Annotation: Dimension
  3. Widget Annotation: Margin
  4. Widget Annotations: Axis Range
  5. Widget Color
  6. Navigation expressions
'has global dashboard': stategroup (
	'yes' {
		'dashboard': [ dashboard: global ] component 'dashboard'
	}
	'no' { }
)
'annotations': component 'extended annotations'
'numerical type annotations': dictionary { [ numerical-type: ]
	'type': stategroup (
		'currency' { [ currency ] }
		'scientific' { [ scientific ] }
		'engineering' { [ engineering ] }
	)
}

Dashboard

Dashboards use a grid layout. The grid needs to be configured with a cell width and cell height. Optionally a gap between cells can be configured. Widgets are placed on the grid with a coordinate and a size in cells. The upper left cell of the grid is at coordinate (1, 1). Optionally the size and margin of a widget can be explicitly set. Widgets with axes should be provided with a margin as the axes and labels are placed in the margin. Each widget has a context node, all paths are relative to this node.

'dashboard' {
	'cell width': [ ( ] group {
		'size': integer
		'unit': stategroup (
			'pixels' { [ px ] }
		)
	}
	'cell height': [ , ] group {
		'size': integer
		'unit': stategroup (
			'pixels' { [ px ] }
		)
	}
	'grid gap': stategroup (
		'yes' { [ ,, ) ]
			'size': integer
			'unit': stategroup (
				'pixels' { [ px ] }
			)
		}
		'no' { [ ) ] }
	)
	'widgets': dictionary {
		'has successor': stategroup = node-switch successor (
			| node = 'yes' { 'successor' = successor }
			| none = 'no'
		)
		'x': [ ( ] integer
		'width': [ / ] integer
		'y': [ , ] integer
		'height': [ /, ) ] integer
		'dimension': component 'dashboard ui dimension'
		'margin': component 'dashboard ui margin'
		'context path': component 'conditional path'
		'graph type': [ : ] stategroup (
			'number' { [ number ]
				'value': [ # ] reference
				'size': stategroup (
					'large' { }
					'fixed' { [ size: ]
						'number size': stategroup (
							'large' { }
							'fixed' {
								'value': integer
							}
						)
						'unit size': stategroup (
							'auto' { }
							'fixed' { [ , ]
								'value': integer
							}
						)
					}
				)
			}
			'range' {
				'chart type': stategroup (
					'progress bar' { [ progress ] }
					'gauge' { [ gauge ] }
				)
				'range start': [ ranges: ] stategroup (
					'static' {
						'value': integer
					}
					'dynamic' {
						'value': [ # ] reference
					}
				)
				'ranges': component 'dashboard ranges'
				'value': [ value: # ] reference
			}
			'pie chart' { [ pie-chart ]
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
							'color': [ , ] component 'dashboard color'
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'label path': [ label: ] component 'conditional path'
						'label property': [ : ] reference
						'value path': [ value: ] component 'conditional path'
						'value property': [ # ] reference
						'merge small slices': stategroup (
							'yes' { [ merge ]
								'below percentage': [ below, % ] integer
							}
							'no' { }
						)
					}
				)
				'sorting': stategroup (
					'yes' { [ sort: ]
						'direction': stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
					}
					'no' { }
				)
			}
			'bar chart' { [ bar-chart ]
				'axis': component 'dashboard axis range'
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
							'color': [ , ] component 'dashboard color'
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'label path': [ label: ] component 'conditional path'
						'label property': [ : ] reference
						'value path': [ value: ] component 'conditional path'
						'value property': [ # ] reference
					}
				)
				'sorting': stategroup (
					'yes' { [ sort: ]
						'direction': stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
					}
					'no' { }
				)
			}
			'grouped bar chart' { [ grouped-bar-chart ]
				'axis': component 'dashboard axis range'
				'collection': component 'collection path'
				'limit': stategroup (
					'custom' { [ limit: ]
						'max entries': integer
					}
					'default' { }
				)
				'label path': [ label: ] component 'conditional path'
				'label property': [ : ] reference
				'values': [ (, ) ] dictionary {
					'has successor': stategroup = node-switch successor (
						| node = 'yes' { 'successor' = successor }
						| none = 'no'
					)
					'value path': [ : ] component 'conditional path'
					'value property': [ # ] reference
					'color': [ , ] component 'dashboard color'
				}
				'has value': stategroup = node-switch .'values' (
					| nodes = 'yes' { 'first' = first }
					| none  = 'no'
				)
				'sorting': stategroup (
					'yes' { [ sort: ]
						'direction': stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
						'axis': stategroup (
							'single' {
								'axis': reference
							}
							'sum' { [ sum ] }
						)
					}
					'no' { }
				)
			}
			'stacked bar chart' { [ stacked-bar-chart ]
				'axis': component 'dashboard axis range'
				'collection': component 'collection path'
				'limit': stategroup (
					'custom' { [ limit: ]
						'max entries': integer
					}
					'default' { }
				)
				'label path': [ label: ] component 'conditional path'
				'label property': [ : ] reference
				'values': [ (, ) ] dictionary {
					'has successor': stategroup = node-switch successor (
						| node = 'yes' { 'successor' = successor }
						| none = 'no'
					)
					'value path': [ : ] component 'conditional path'
					'value property': [ # ] reference
					'color': [ , ] component 'dashboard color'
				}
				'has value': stategroup = node-switch .'values' (
					| nodes = 'yes' { 'first' = first }
					| none  = 'no'
				)
				'sorting': stategroup (
					'yes' { [ sort: ]
						'direction': stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
						'axis': stategroup (
							'single' {
								'axis': reference
							}
							'sum' { [ sum ] }
						)
					}
					'no' { }
				)
			}
			'line chart' { [ line-chart ]
				'axis': component 'dashboard axis range'
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
						'color': [ , ] component 'dashboard color'
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'sort path': [ sort: ] component 'conditional path'
						'sort property': [ # ] reference
						'sort direction': [ , ] stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value path': [ : ] component 'conditional path'
							'value property': [ # ] reference
							'color': [ , ] component 'dashboard color'
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
				)
			}
			'area chart' { [ area-chart ]
				'axis': component 'dashboard axis range'
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
						'color': [ , ] component 'dashboard color'
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'sort path': [ sort: ] component 'conditional path'
						'sort property': [ # ] reference
						'sort direction': [ , ] stategroup (
							'ascending' { [ ascending ] }
							'descending' { [ descending ] }
						)
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value path': [ : ] component 'conditional path'
							'value property': [ # ] reference
							'color': [ , ] component 'dashboard color'
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
				)
			}
			'scatter chart' { [ scatter-chart ]
				'collection': component 'collection path'
				'limit': stategroup (
					'custom' { [ limit: ]
						'max entries': integer
					}
					'default' { }
				)
				'label x': [ axis-x: ] text
				'value x path': [ , ] component 'conditional path'
				'value x property': [ # ] reference
				'axis x': component 'dashboard axis range'
				'label y': [ axis-y: ] text
				'value y path': [ , ] component 'conditional path'
				'value y property': [ # ] reference
				'axis y': component 'dashboard axis range'
			}
			'bubble chart' { [ bubble-chart ]
				'collection': component 'collection path'
				'limit': stategroup (
					'custom' { [ limit: ]
						'max entries': integer
					}
					'default' { }
				)
				'label x': [ axis-x: ] text
				'value x path': [ , ] component 'conditional path'
				'value x property': [ # ] reference
				'axis x': component 'dashboard axis range'
				'label y': [ axis-y: ] text
				'value y path': [ , ] component 'conditional path'
				'value y property': [ # ] reference
				'axis y': component 'dashboard axis range'
				'value z path': [ size: ] component 'conditional path'
				'value z property': [ # ] reference
				'axis z': component 'dashboard axis range'
			}
			'connected scatter chart' { [ connected-scatter-chart ]
				'collection': component 'collection path'
				'limit': stategroup (
					'custom' { [ limit: ]
						'max entries': integer
					}
					'default' { }
				)
				'sort path': [ sort: ] component 'conditional path'
				'sort property': [ # ] reference
				'sort direction': [ , ] stategroup (
					'ascending' { [ ascending ] }
					'descending' { [ descending ] }
				)
				'label x': [ axis-x: ] text
				'value x path': [ , ] component 'conditional path'
				'value x property': [ # ] reference
				'axis x': component 'dashboard axis range'
				'label y': [ axis-y: ] text
				'value y path': [ , ] component 'conditional path'
				'value y property': [ # ] reference
				'axis y': component 'dashboard axis range'
			}
			'spider chart' { [ spider-chart ]
				'axis': component 'dashboard axis range'
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
						'color': [ , ] component 'dashboard color'
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'label path': [ label: ] component 'conditional path'
						'label property': [ : ] reference
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value path': [ : ] component 'conditional path'
							'value property': [ # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
				)
			}
			'radar chart' { [ radar-chart ]
				'axis': component 'dashboard axis range'
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value': [ : # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
						'color': [ , ] component 'dashboard color'
					}
					'dynamic' {
						'collection': component 'collection path'
						'limit': stategroup (
							'custom' { [ limit: ]
								'max entries': integer
							}
							'default' { }
						)
						'label path': [ label: ] component 'conditional path'
						'label property': [ : ] reference
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'value path': [ : ] component 'conditional path'
							'value property': [ # ] reference
						}
						'has value': stategroup = node-switch .'values' (
							| nodes = 'yes' { 'first' = first }
							| none  = 'no'
						)
					}
				)
			}
			'legend' { [ legend ]
				'binding': stategroup (
					'static' {
						'values': [ (, ) ] dictionary {
							'has successor': stategroup = node-switch successor (
								| node = 'yes' { 'successor' = successor }
								| none = 'no'
							)
							'color': [ : ] component 'dashboard color'
						}
					}
					'dynamic' {
						'collection': component 'collection path'
						'label path': [ label: ] component 'conditional path'
						'label property': [ : ] reference
					}
				)
			}
		)
	}
}

Widget: integer

Displays a single number found directly under the context node in a (by default) large font. The label of the numerical type is also shown, by default in the normal font size.

Widget: Progress bar

Displays a bar which fills the closer the current value is to the end of the range. The range of the bar can be split into several segments, each defining a different color. The bar is given the color of the range the current value is in.

Widget: Gauge

Displays a gauge with an indicator where the current value is in the range. The range can be split into several segments, each defining a different color. The label of the numerical type is also shown on the gauge.

Widget: Pie Chart

Displays a pie chart. It creates a slice for each entry in the query result. A label and value for each entry must be provided. Optionally a threshold can be set, slice which occupy less percentage then the threshold are merged in a single ‘other’ slice. The entries can optionally be sorted. As pie charts can not show non-existing (value = 0) or negative values, it can only plot positive numbers.

Widget: Bar Chart

Displays a simple bar chart. It creates a single bar for each entry in the query result. A label and value for each entry must be provided. The entries can optionally be sorted. Bar charts always show an y-axis starting at 0, negative values are not shown.

Widget: Grouped Bar Chart

Displays a bar chart like the normal bar chart widget, expect it creates multiple bars for each entry in the query result. A label and one or more values for each entry must be provided. A color must be provided for each value. As all values share the same y-axis, the numerical types of all values must be equal. The entries can optionally be sorted, either on a specific value or the sum of all their values. Bar charts always show an y-axis starting at 0, negative values are not shown.

Widget: Stacked Bar Chart

Displays a bar chart like the normal bar chart widget, expect it separates the bar into multiple segments for each entry in the query result. A label and one or more values for each entry must be provided. A color must be provided for each value. As all values share the same y-axis, the numerical types of all values must be equal. The entries can optionally be sorted, either on a specific value or the sum of all their values. Bar charts always show an y-axis starting at 0. Negative values cases bars to be placed on top of each other instead of stack on each other and are filter from the set.

Widget: Line Chart

Displays a line chart. It creates a single line for each value. Every entry in the query result adds a point to the line. A sort criteria must be provided as the data has no inherit order. This sets to order of the entries in the query result and is not displayed as line. As all values share the same y-axis, the numerical types of all values must be equal.

Widget: Area Chart

Displays an area chart. It creates a single line for each value and fills the area between the line and 0 on the y-axis. Every entry in the query result adds a point to the line. A sort criteria must be provided as the data has no inherit order. This sets to order of the entries in the query result and is not displayed as line. As all values share the same y-axis, the numerical types of all values must be equal.

Widget: Scatter Chart

Displays a large amount of dots. It creates a single dot for each entry in the query result. Two values for each entry must be provided, one for the x-axis and the other for the y-axis. The dots are rendered partially transparent in the accent color.

Widget: Bubble Chart

Displays a number of dots like the scatter chart widget, but it takes an additional value for each entry in the query result for the size of the dot.

Widget: Connected Scatter Chart

Displays a number of dots like the scatter chart widget, but it also renders a line connecting the varies dots. A sort criteria must be provided as the data has no inherit order. The dots are rendered partially transparent in the accent color. The line is rendered solid in the accent color.

Widget: Spider Chart

Displays a spider chart. It either creates one area for the context node or creates an area for each entry in the query result. Three or more values for each entry must be provided, one axis is generated for each value. As all values share the same axis scale, the numerical types of all values must be equal. The axes always start a 0, negative values are not shown.

Widget: Radar Chart

Displays a radar chart. This is mostly identical to the spider chart. Unlike the spider chart, the grid is rendered with circles and the areas use rounded corners.

Widget: Legend

Displays a legend either for a set of value color pairs or for all entries in a query result. The query variant automatically assigns colors to the labels use the same algorithm as most of the charts.

Widget Annotation: Dimension

Allows the default size of a widget to be changed. All values are in pixels.

'dashboard ui dimension' {
	'dimension': stategroup (
		'custom' { [ @size(, ) ]
			'x': integer
			'y': [ , ] integer
		}
		'default' { }
	)
}

Widget Annotation: Margin

Allows the default margin of a widget to be changed. All values are in pixels.

'dashboard ui margin' {
	'margin': stategroup (
		'custom' { [ @margin(, ) ]
			'x1': integer
			'x2': [ , ] integer
			'y1': [ , ] integer
			'y2': [ , ] integer
		}
		'default' { }
	)
}

Widget Annotations: Axis Range

Allows the range of any axis to be changed. By default the axis range is dynamically calculated based on the data. When providing a hint, the provided value is guaranteed to be on axis, but the range might be increased beyond the hint to prevent data from going out of bounds of the axis. A static axis ignores all data and while always have the exact range as provided.

'dashboard axis range' {
	'custom range': stategroup (
		'yes' { [ @range(, ) ]
			'min anchor': stategroup (
				'static' { [ force ]
					'value': integer
				}
				'hint' {
					'value': integer
				}
				'dynamic' { }
			)
			'max anchor': [ , ] stategroup (
				'static' { [ force ]
					'value': integer
				}
				'hint' {
					'value': integer
				}
				'dynamic' { }
			)
		}
		'no' { }
	)
}
'dashboard ranges' {
	'type': stategroup (
		'green' { [ green ] }
		'blue' { [ blue ] }
		'orange' { [ orange ] }
		'red' { [ red ] }
	)
	'range size': stategroup (
		'static' {
			'value': integer
		}
		'dynamic' {
			'value': [ # ] reference
		}
	)
	'has more': stategroup (
		'yes' { [ , ]
			'tail': component 'dashboard ranges'
		}
		'no' { }
	)
}

Widget Color

Allows the selection of a color. This can either be a predefined color or a custom color. Predefined colors are provided by the color theme. Custom colors are not bound to the theme and can be any CSS color, for example: #FF8000, rgb(100%, 50%, 0%) and hsl(30deg, 100%, 50%) all specify the same shade of orange.

'dashboard color' {
	'color': stategroup (
		'blue' { [ blue ] }
		'orange' { [ orange ] }
		'green' { [ green ] }
		'red' { [ red ] }
		'black' { [ black ] }
		'grey' { [ grey ] }
		'grey light' { [ grey light ] }
		'grey dark' { [ grey dark ] }
		'teal' { [ teal ] }
		'purple' { [ purple ] }
		'hex' {
			'value': text
		}
	)
}
'singular path' {
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'group' {
					'group': [ . ] reference
				}
			)
			'tail': component 'singular path'
		}
		'no' { }
	)
}
'conditional path' {
	'head': component 'singular path'
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'state' {
					'state group': [ . ] reference
					'state': [ ? ] reference
				}
			)
			'tail': component 'conditional path'
		}
		'no' { }
	)
}
'collection path' {
	'head': component 'conditional path'
	'collection': [ ., [] ] reference
	'has more steps': stategroup (
		'yes' {
			'tail': component 'collection path'
		}
		'no' { }
	)
}
'query path' {
	'has steps': stategroup (
		'yes' {
			'type': stategroup (
				'parent' { [ ^ ] }
				'reference' {
					'reference': [ > ] reference
					'result': stategroup (
						'referenced node' { }
						'rule' {
							'rule': [ $ ] reference
						}
					)
				}
				'group' {
					'group': [ + ] reference
				}
				'state' {
					'state group': [ ? ] reference
					'state': [ | ] reference
				}
			)
			'tail': component 'query path'
		}
		'no' { }
	)
}
'extended annotations' { [ (, ) ]
	'has inline dashboards': stategroup (
		'yes' {
			'inline dashboards': dictionary { [ dashboard: ]
				'has more inline dashboards': stategroup = node-switch successor (
					| node = 'yes' { 'next inline dashboard' = successor }
					| none = 'no'
				)
				'dashboard': [ (, ) ] component 'dashboard'
			}
		}
		'no' { }
	)
	'has handheld frames': stategroup (
		'yes' {
			'handheld frames': dictionary { [ handheld: ]
				'frame': component 'handheld view frame'
			}
			'main frame': reference = first
		}
		'no' { }
	)
	'properties': dictionary {
		'type': [ : ] stategroup (
			'command' { [ command ]
				'annotations': component 'extended annotations'
			}
			'action' { [ action ]
				'annotations': component 'extended annotations'
			}
			'group' { [ group ]
				'annotations': component 'extended annotations'
			}
			'reference set' { [ reference-set ]
				'custom queries': component 'custom queries'
			}
			'collection' { [ collection ]
				'entries are custom properties': stategroup (
					'yes' { [ @properties ]
						'type': stategroup (
							'value' {
								'value attribute': [ value: ] reference
							}
							'node' { [ node ] }
						)
					}
					'list' { [ @list ] }
					'no' { }
				)
				'custom queries': component 'custom queries'
				'sub tree': stategroup (
					'yes' {
						'annotations': component 'extended annotations'
					}
					'no' { }
				)
			}
			'stategroup' { [ stategroup ]
				'derived': stategroup (
					'no' { }
					'yes' { [ @derived ] }
				)
				'states': [ (, ) ] dictionary { [ | ]
					'annotations': component 'extended annotations'
				}
			}
			'text' { [ text ]
				'derived': stategroup (
					'no' { }
					'yes' { [ @derived ] }
				)
			}
			'number' { [ number ]
				'summarize': stategroup (
					'no' { }
					'total' { [ @show-total ] }
				)
				'derived': stategroup (
					'no' { }
					'yes' { [ @derived ] }
				)
			}
		)
	}
}
'custom queries' {
	'has custom queries': stategroup (
		'yes' {
			'custom queries': dictionary { [ query ]
				'has more queries': stategroup = node-switch successor (
					| node = 'yes' { 'next query' = successor }
					| none = 'no'
				)
				'properties': [ [, ] ] dictionary {
					'has more properties': stategroup = node-switch successor (
						| node = 'yes' { 'next property' = successor }
						| none = 'no'
					)
					'context path': [ -> ] component 'query path'
					'type': [ : ] stategroup (
						'stategroup' { [ stategroup ]
							'property': reference
							'filter': stategroup (
								'yes' { [ filter ]
									'states': [ ? ] dictionary { [ | ]
										'is selected': stategroup (
											'yes' { [ selected ] }
											'no' { }
										)
									}
								}
								'no' { }
							)
						}
						'number' { [ number ]
							'property': reference
							'filter': stategroup (
								'yes' { [ filter ]
									'operator': stategroup (
										'smaller' { [ < ] }
										'smaller equal' { [ <= ] }
										'greater' { [ > ] }
										'greater equal' { [ >= ] }
										'equal' { [ == ] }
									)
									'criteria': stategroup (
										'now' { [ now ]
											'offset': [ + ] integer
										}
										'static' {
											'value': integer
										}
									)
								}
								'no' { }
							)
						}
						'text' { [ text ]
							'property': reference
							'filter': stategroup (
								'yes' { [ filter ]
									'criteria': text
								}
								'no' { }
							)
						}
						'file' { [ file ]
							'property': reference
						}
						'action' { [ action ]
							'attribute': reference
						}
						'command' { [ command ]
							'attribute': reference
						}
					)
				}
				'custom sorting': stategroup (
					'yes' {
						'direction': stategroup (
							'ascending' { [ @ascending: ] }
							'descending' { [ @descending: ] }
						)
						'type': stategroup (
							'number' {
								'number': [ # ] reference
							}
							'text' {
								'text': [ . ] reference
							}
						)
					}
					'no' { }
				)
			}
		}
		'no' { }
	)
}
'annotated collection selector' {
	'has step': stategroup (
		'yes' {
			'property': [ . ] reference
			'type': stategroup (
				'group' { }
				'collection' { [ [] ] }
				'state' {
					'state': [ ? ] reference
				}
			)
			'tail': component 'annotated collection selector'
		}
		'no' {
			'property': [ ., [] ] reference
		}
	)
}
'handheld frame selector' {
	'type': stategroup (
		'inline' {
			'frame': component 'handheld view frame'
		}
		'annotated' {
			'frame': reference
		}
	)
}
'handheld view details' {
	'title': stategroup (
		'yes' {
			'property': [ title: ] component 'handheld view descriptor'
		}
		'no' { }
	)
	'fields': dictionary {
		'has more fields': stategroup = node-switch successor (
			| node = 'yes' { 'next field' = successor }
			| none = 'no'
		)
		'emphasis': [ : ] stategroup (
			'yes' { [ @emphasis ] }
			'no' { }
		)
		'property': component 'handheld view descriptor'
	}
}
'handheld view elements' {
	'has element': stategroup (
		'yes' {
			'type': [ -> ] stategroup (
				'label' { [ label: ]
					'text': reference
				}
				'inline view' { [ inline view: ]
					'frame': component 'handheld frame selector'
				}
				'view' {
					'view': component 'handheld view selector'
				}
			)
			'tail': component 'handheld view elements'
		}
		'no' { }
	)
}
'handheld view frame' {
	'type': stategroup (
		'decision' { [ (, ) ]
			'options': dictionary {
				'has more options': stategroup = node-switch successor (
					| node = 'yes' { 'next option' = successor }
					| none = 'no'
				)
				'emphasis': [ : ] stategroup (
					'low' { }
					'medium' { [ @emphasis: medium ] }
					'high' { [ @emphasis: high ] }
				)
				'frame': component 'handheld frame selector'
			}
		}
		'collection navigation' { [ collection (, ) ]
			'collection context': [ path: ] stategroup (
				'this' { }
				'root' { [ root ] }
			)
			'path': component 'annotated collection selector'
			'header': stategroup (
				'yes' { }
				'no' { [ @no-header ] }
			)
			'layout': stategroup (
				'set' { [ @layout: ]
					'type': stategroup (
						'tabular' { [ tabular ] }
						'cards' { [ cards ] }
					)
				}
				'default' { }
			)
			'details': stategroup (
				'yes' {
					'details': component 'handheld view details'
				}
				'no' {
					'property': [ label: ] component 'handheld view descriptor'
				}
			)
			'filters': stategroup (
				'yes' { [ filters: ]
					'fields': dictionary {
						'has more fields': stategroup = node-switch successor (
							| node = 'yes' { 'next field' = successor }
							| none = 'no'
						)
						'path': [ : ] component 'query path'
						'property': [ . ] reference
						'type': stategroup (
							'stategroup' {
								'filter': stategroup (
									'state' {
										'state': [ is ] reference
									}
									'not state' {
										'state': [ is not ] reference
									}
									'states' {
										'states': [ is (, ) ] dictionary { }
									}
									'simple' { [ stategroup ] }
								)
							}
							'number' {
								'filter': stategroup (
									'match' {
										'operator': stategroup (
											'smaller' { [ smaller ] }
											'smaller equal' { [ smaller or equal ] }
											'greater' { [ greater ] }
											'greater equal' { [ greater or equal ] }
											'equal' { [ equal ] }
										)
										'type': [ than ] stategroup (
											'now' { [ now + ] }
											'static' { }
										)
										'offset': integer
									}
									'simple' { [ number ] }
								)
							}
							'text' {
								'filter': stategroup (
									'pattern' {
										'criteria': [ match ] text
									}
									'simple' { [ text ] }
									'current node' { [ this ] }
								)
							}
						)
					}
				}
				'no' { }
			)
			'sort': stategroup (
				'yes' { [ sort: ]
					'path': component 'query path'
					'property': component 'handheld view property'
					'direction': stategroup (
						'ascending' { [ ascending ] }
						'descending' { [ descending ] }
					)
				}
				'no' { }
			)
			'action': stategroup (
				'yes' { [ view: ]
					'emphasis': stategroup (
						'low' { }
						'medium' { [ @emphasis: medium ] }
						'high' { [ @emphasis: high ] }
					)
					'view': component 'handheld view selector'
				}
				'no' { }
			)
		}
		'group navigation' {
			'property': [ . ] reference
			'frame': component 'handheld frame selector'
		}
		'state navigation' {
			'property': [ . ] reference
			'state': [ ? ] reference
			'frame': component 'handheld frame selector'
		}
		'reference navigation' {
			'text': [ > ] reference
			'frame': component 'handheld frame selector'
		}
		'pivot view' { [ pivot (, ) ]
			'options': group { dynamic-order
				'show crosshair': stategroup (
					'yes' { [ @crosshair ] }
					'no' { }
				)
				'show grid': stategroup (
					'yes' { [ @grid ] }
					'no' { }
				)
			}
			'columns': [ columns: . ] reference
			'column grouping': [ : ] reference
			'column label': [ label: ] component 'handheld view descriptor'
			'cells': [ cells: . ] reference
			'row grouping': [ : ] reference
			'row label': [ label: ] component 'handheld view descriptor'
			'content': stategroup (
				'inline view' { [ inline view: ]
					'frame': component 'handheld frame selector'
				}
				'label' { [ label: ]
					'property': component 'handheld view descriptor'
				}
			)
		}
		'detail view' { [ details (, ) ]
			'details': component 'handheld view details'
			'elements': component 'handheld view elements'
		}
		'command view' { [ command (, ) ]
			'details': component 'handheld view details'
			'selection': [ view: ] stategroup (
				'button' {
					'emphasis': stategroup (
						'low' { }
						'medium' { [ @emphasis: medium ] }
						'high' { [ @emphasis: high ] }
					)
				}
				'scan' { [ @scan (, ) ]
					'referencer': group {
						'path': component 'conditional path'
						'collection': [ ., [] ] reference
					}
					'path': [ using: ] component 'conditional path'
					'search property': [ . ] reference
				}
			)
			'view': component 'handheld view selector'
		}
	)
}
'handheld view descriptor' {
	'type': stategroup (
		'dynamic' {
			'property': component 'handheld view property selector'
		}
		'static text' {
			'text': reference
		}
	)
	'has tail': stategroup (
		'yes' { [ , ]
			'tail': component 'handheld view descriptor'
		}
		'no' { }
	)
}
'handheld view property' {
	'property': [ . ] reference
	'style': stategroup (
		'default' { }
		'barcode' { [ @barcode: ]
			'barcode type': stategroup (
				'CODE128' { [ CODE128 ] }
				'CODE128A' { [ CODE128A ] }
				'CODE128B' { [ CODE128B ] }
				'CODE128C' { [ CODE128C ] }
				'EAN13' { [ EAN13 ] }
				'EAN8' { [ EAN8 ] }
				'EAN5' { [ EAN5 ] }
				'EAN2' { [ EAN2 ] }
				'UPCA' { [ UPCA ] }
				'UPCE' { [ UPCE ] }
				'CODE39' { [ CODE39 ] }
				'ITF' { [ ITF ] }
				'ITF14' { [ ITF14 ] }
				'MSI10' { [ MSI10 ] }
				'MSI11' { [ MSI11 ] }
				'MSI1010' { [ MSI1010 ] }
				'MSI1110' { [ MSI1110 ] }
				'Pharmacode' { [ Pharmacode ] }
				'Codabar' { [ Codabar ] }
			)
		}
		'qrcode' { [ @qrcode ] }
	)
}
'handheld view property selector' {
	'type': stategroup (
		'switch' {
			'stategroup': [ . ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'tail': component 'handheld view property selector'
			}
		}
		'step' {
			'type': stategroup (
				'group' {
					'group': [ . ] reference
				}
				'state' {
					'stategroup': [ . ] reference
					'state': [ ? ] reference
				}
				'reference' {
					'text': [ > ] reference
				}
				'parent' { [ ^ ] }
			)
			'tail': component 'handheld view property selector'
		}
		'property' {
			'property': component 'handheld view property'
		}
	)
}
'handheld command annotations' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'group' { [ group ]
				'parameters': component 'handheld command annotations'
			}
			'collection' { [ collection ]
				'parameters': component 'handheld command annotations'
			}
			'stategroup' { [ stategroup (, ) ]
				'states': dictionary {
					'parameters': component 'handheld command annotations'
				}
			}
			'text' { [ text ]
				'style': stategroup (
					'buttons' { [ @button ] }
					'keyboard' { [ @keyboard ] }
					'default' { }
					'scan' { [ @scan using: ]
						'path': component 'conditional path'
						'search property': [ . ] reference
					}
				)
			}
		)
	}
}
'handheld view context' {
	'has step': stategroup (
		'yes' { [ ^ ]
			'tail': component 'handheld view context'
		}
		'no' { }
	)
}
'handheld view selector' {
	'type': stategroup (
		'switch' {
			'property': [ . ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'tail': component 'handheld view selector'
			}
		}
		'step' {
			'type': stategroup (
				'group' {
					'property': [ . ] reference
				}
				'state' {
					'property': [ . ] reference
					'state': [ ? ] reference
				}
				'reference' {
					'text': [ > ] reference
				}
			)
			'tail': component 'handheld view selector'
		}
		'command' {
			'command': [ command: ] reference
			'annotations': group { dynamic-order
				'auto execute': stategroup (
					'yes' { [ @auto-execute ] }
					'no' { }
				)
				'close after execute': stategroup (
					'yes' { }
					'no' { [ @keep-open ] }
				)
				'emphasis': stategroup (
					'low' { }
					'medium' { [ @emphasis: medium ] }
					'high' { [ @emphasis: high ] }
				)
			}
			'parameter annotations': stategroup (
				'yes' {
					'parameters': component 'handheld command annotations'
				}
				'no' { }
			)
			'title': stategroup (
				'binding' { [ (, ) ]
					'property': [ . ] reference
				}
				'custom' { [ (, ) ]
					'title': reference
				}
				'default' { }
			)
			'open view': stategroup (
				'yes' { [ and ]
					'context': component 'handheld view context'
					'frame': component 'handheld frame selector'
				}
				'no' { }
			)
		}
		'view' {
			'emphasis': [ : ] stategroup (
				'low' { }
				'medium' { [ @emphasis: medium ] }
				'high' { [ @emphasis: high ] }
			)
			'context': component 'handheld view context'
			'frame': component 'handheld frame selector'
			'title': stategroup (
				'binding' { [ (, ) ]
					'property': [ . ] reference
				}
				'custom' { [ (, ) ]
					'title': reference
				}
				'default' { }
			)
		}
	)
}