Processing¶
A competition requires an evaluation, an evaluation. This consists of three Javascript functions that describe the life cycle of the competition. To understand how they work, it is useful to first understand the basic functionality.
Basics¶
During a competition, each competitor’s devices deliver an endless stream of device events that are sent to the sports server. From the system’s point of view, a participant is therefore nothing more than a data record with a name, avatar, … and above all: an endless stream of waypoints.
The time measurement alone determines which of these waypoints are relevant and which can be ignored. There are several time stamps that are important:
- The entire competition has a start and end timestamp. Only events that lie within this period are relevant at all - Each participant is subjected to several time measurements. Only events that take place during an active measurement of the competitor are relevant.
A ranking data record is saved for each participant for each competition. This data record is recalculated for each incoming event that takes place during a time measurement. The developer of the reducer is completely free to decide which data is saved in this data record. An initial data set is created at the start of the competition (or at the first time measurement) and this data set is changed for each incoming device event.
The sports server evaluates these data sets at regular intervals to calculate a ranking and display this ranking.
A competition looks like this:
- Initialisation of a data set per participant - For each incoming device event, this data set is mutated by calling a user-defined function to which the current data set and the current event are passed as parameters - A new ranking is calculated and published at regular intervals
Code¶
In the following, an example code is to be developed which can serve as a basis for developing your own reducers. The system to be developed is intended to represent a ranking which selects the participant with the highest speed as the winner.
Initialisation¶
The initialisation function must have the name initValue
and return a data structure which serves as the initial value for a participant.
1 2 3 4 5 |
|
The code returns an object which provides the field maxspeed
and initialises it with the value 0
, i.e. for each participant a data record of the form
1 2 3 |
|
Reducer¶
If the subscriber’s device now supplies a signal, the reduce
function is called. This function receives the current data set data
and the device signal event
as parameters.
While the structure of the data
parameter should be known to the developer (the initial value is generated with the initValue
), an event has the following structure:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
To select the participant with the highest speed as the winner in the ranking list, the ‘reduce’ function must memorise the highest speed:
1 2 3 4 5 6 7 8 9 |
|
It is only checked here whether the speed contained in the device data record is greater than the speed saved in the subscriber data record. If this is the case, this speed is saved as the new maximum speed. The jslog
function can be used to generate log outputs that can be displayed or tracked in the Sports app.
Each data set sent from the device is reduced to one participant data set using the reduce
function, i.e. the incoming stream of events is compressed to a single data set. In this simple example it is simply the maximum speed, but of course there are endless possibilities here.
Ranking¶
Ultimately, however, a ranking list is required, which must also be sorted by the sports app. To ensure that this sorting and display is independent of the user-defined data structure, a third function must be made available, the rankValue
.
1 2 3 4 5 6 7 |
|
This function returns a triple with three integers. The participants are then sorted in such a way that the one with the highest score at index 0 is the winner. If there are several participants with the same value, sorting is based on index 1 and if this is also the same, index 2 is used. If all three values are the same, the participants are considered to have the same score.
In the above example, the saved speed is multiplied by 100, as this is a decimal number that indicates the speed in km/h. This value is then converted to an integer (using the standard JS function parseInt
). The other two values are returned as 0
and can also be omitted in this case, i.e. it would also be sufficient to simply return an array with a single element.
Debugger¶
The system provides an integrated debugging mechanism for developing the reducer
and ranking
functionalities. For this purpose, the functions can be played through with defined events. Each event can be fired as a single step or automatically.
Generator¶
The basis for the debugger is a generator. This is an entity that can generate a stream of events. There are three different generator types:
-
String-based
A JSON array is entered in an edit area, which corresponds to the event format of the platform. The syntax can be checked, but whether the desired events are generated only becomes apparent at runtime. -
Database-based
Events can also be selected directly from the database. Two time stamps (start, end) and the source (Comeptition
,Team
,Participant
) are selected for this. The system retrieves the corresponding events and stores them redundantly in chronological order. Caution: With large time periods, this can lead to it taking longer for all data to be buffered. In addition, a lot of space is taken up in the database, i.e. large DB generators should only be used for replays and then deleted again. -
GPX based
Various GPX data can be uploaded here from which tracking data can be extracted. An IMEI, a timestamp and an interval are required for each piece of data. The system then generates a list of events from the positions, the IMEI and the time information. If desired, this list can then be converted into a string-based generator, so that individual attributes of the events can be adjusted manually.
Once a suitable generator has been created, it can be used to debug an evaluation.
Debugger data¶
The debugger expects three fields that can/must be filled:
- Start timestamp
So-calledmeasurements
can be accessed in areducer
. These are time measurements that are created when the measurement is started. If thereducer
requires a measurement, a time measurement can be created by specifying the timestamp, which can then be queried in the code. If the code does not require this, the field can be left empty. - Competition
All currently available competitions are displayed in the list. The debugger needs these to create a suitable ranking for all participants, which is then filled with data by thereducer
. - Generator
The generator delivers a stream of events.
Initialisation¶
The debug session is started by clicking on Reset
The system loads the events from the generator and displays a section of them. The data set highlighted in yellow is always the next one to be executed.
With the buttons 1x
, 2x
… one, two, … events can be executed against the reducer.
Directly below the list of events is an output area for the logs of the reducer
and below this is the runtime data of the competition
. By selecting a participant in the drop-down list, the display of the data can be restricted to this participant. The PLUS
button can be used to create several such display areas, each of which may display a specific participant.
Once a debug session has run through (all events), it can be restarted by pressing Reset
.
Step-by-step debugging¶
After a debug step, the list of events shows the new (future) record in yellow, the output shows any logs and the data area shows the data of the selected participants:
The data area always consists of a structure with the following values:
-
value1
…value3
These values are the results of the rank function -
userdata
The user data area contains the data that the reducer returns after each step.
Autoplay¶
With the help of automatic debugging, the events from the generator can be processed in chronological order. Attention: The events all contain a Sent
timestamp, i.e. the speed at which the events are processed should not influence the logic of the reducer.
If the debugger is running in automatic mode, the pause button can be pressed at any time and then resumed in single-step mode.
Provided objects¶
As can be seen in the example, the current data set and the current event are always passed to the reducer
function. In addition to this data, other data is also available in the function.
Logging¶
There is a function jslog
with which log outputs can be carried out. The signature of the function is
1 |
|
The first parameter is therefore a log message, followed by key/value pairs, whereby the key must be a string and the value is freely definable. The example above contained the following call:
1 |
|
Here new maxspeed found
is the log message; then follow the key/value pairs ("event", event)
and ("data",data)
.
Map data¶
Basic data on the displayed map is contained in the variable mapdata
.
mapdata.name
The name of the competition -mapdata.baselayer
The name of the set layer -mapdata.opacity
The value of the set opacity -mapdata.zoomlevel
The value of the set zoom level -mapdata.location
The position of the competition marker
In addition, mapdata
also contains the saved courses and regions with the names that were specified in the system. A course is a collection of lines and the course has an intersects
function, e.g. mapdata.finish.intersects
.
mapdata.Finish.intersects(pos1, pos2)
If there is a course with the nameFinish
, this function can be used to query whether this course intersects with a connecting line from the two transferred positions (events can also be transferred directly; the system automatically extracts the position there).
With a region, there is a function contains
to which only a single position (or event) is passed. If this position is contained in the region, this function returns the value true
.
Measurement¶
A participant can have several time measurements. The measurement
object is used to request these. This provides a function getAt
, which returns the time measurement for the specified device event.
1 |
|
This code asks the system for the start of the time measurement for the current device event. The start
attribute is a javascript data object with the timestamp, which can be used if a race is started with a fixed mass start and a clear signal, for example.
Race¶
It is possible to stop the time measurement via the race
object; the stop(evt)
function, which requires an event as a parameter, is used for this purpose. If this function is called, the time measurement for the device contained in the event is ended and the sent
timestamp is used as the end of the time measurement. Example
1 2 3 4 |
|