Warning: This manual is under a rewriting process and still mostly reflects version 0.8.
Céu is an imperative, concurrent and reactive language in which then lines of execution, known as trails, react together continuously and in synchronous steps to external input events from the environment. Waiting for an event halts the running trail until that event occurs. The environment broadcasts an occurring event to all active trails, which share a single global time reference (the event itself).
The synchronous concurrency model of Céu greatly diverges from conventional multithreading (e.g. pthreads and Java threads) and the actor model (e.g. erlang and Go). On the one hand, trails can share variables in a deterministic and seamless way (e.g. no need for locks or semaphores). On the other hand, there is no real parallelism (e.g. multi-core execution) in the standard synchronous execution mode of the language.
Céu integrates well with C, being possible to define and call C functions from within Céu programs.
Céu is free software.
Céu is grounded on a precise definition of logical time as a discrete sequence of external input events: a sequence because only a single input event is handled at a logical time; discrete because reactions to events are guaranteed to execute in bounded real time (see Bounded execution).
The execution model for Céu programs is as follows:
(1 Trails can be created with parallel compositions.)
The synchronous execution model of Céu is based on the hypothesis that internal reactions run infinitely faster in comparison to the rate of external events. An internal reaction is the set of computations that execute when an external event occurs. Conceptually, a program takes no time on step 2 and is always idle on step 3. In practice, if a new external input event occurs while a reaction chain is running (step 2), it is enqueued to run in the next reaction. When multiple trails are active at a logical time (i.e. awaking on the same event), Céu schedules them in the order they appear in the program text. This policy is somewhat arbitrary, but provides a priority scheme for trails, and also ensures deterministic and reproducible execution for programs. At any time, at most one trail is executing.
The program and diagram below illustrate the behavior of the scheduler of Céu:
1: input void A, B, C;
2: par/and do // A, B, and C are external input events
3: // trail 1
4: <...> // <...> represents non-awaiting statements
5: await A;
6: <...>
7: with
8: // trail 2
9: <...>
10: await B;
11: <...>
12: with
13: // trail 3
14: <...>
15: await A;
16: <...>
17: await B;
18: par/and do
19: // trail 3
20: <...>
21: with
22: // trail 4
23: <...>
24: end
25: end
The program starts in the boot reaction and splits in three trails (a par/and
rejoins after all trails terminate). Following the order of declaration for the trails, they are scheduled as follows (t0 in the diagram):
await A
(line 5);await B
(line 10);await A
(line 15).As no other trails are pending, the reaction chain terminates and the scheduler remains idle until the event A
occurs (t1 in the diagram):
A
.await B
(line 17).During this reaction, new instances of events A
, B
, and C
occur (t1 in the diagram) and are enqueued to be handled in the reactions that follow. As A
happened first, it is used in the next reaction. However, no trails are awaiting it, so an empty reaction chain takes place (t2 in the diagram). The next reaction dequeues the event B
(t3 in the diagram):
With all trails terminated, the program also terminates and does not react to the pending event C
. Note that each step in the logical time line (t0, t1, etc.) is identified by the event it handles. Inside a reaction, trails only react to that identifying event (or remain suspended).
The use of trails in parallel allows programs to wait for multiple events at the same time. Céu supports three kinds of parallel compositions differing in how they rejoin and proceed to the statement in sequence:
par/and
rejoins after all trails in parallel terminate;par/or
rejoins after any trail in parallel terminates;par
never rejoins (even if all trails terminate).The termination of a trail inside a par/or
aborts the other trails in parallel, which must be necessarily awaiting (from rule 2 of Execution model). Before aborting, a trail has a last opportunity to execute all active finalization statements.
As mentioned in the introduction and emphasized in the execution model, trails inside parallel compositions do not execute with real parallelism. Therefore, inside compositions trails are awaiting in parallel, rather than executing in parallel.
Reaction chains should run in bounded time to guarantee that programs are responsive and can handle upcoming input events from the environment. For any loop statement in a program, Céu requires that every possible path inside its body contains at least one await
or break
statement, thus avoiding tight loops (i.e., unbounded loops that do not await).
In the example below, the if
true branch may never execute, resulting in a tight loop (which the compiler complains about):
loop do
if <cond> then
break;
end
end
For time-consuming algorithms that require unrestricted loops (e.g., cryptography, image processing), Céu provides Asynchronous execution.
TODO (shared memory + deterministic scheduler + optional static analysis)
Céu provides inter-trail communication through internal events. Trails use the await
and emit
operations to manipulate internal events, i.e., a trail that emits an event can awake trails previously awaiting the same event.
An emit
starts a new internal reaction in the program:
emit
, the scheduler remembers the statement following it to execute later (i.e., its continuation).If an awaking trail emits another internal event, a new internal reaction starts. The scheduler uses a stack policy (first in, last out) for saved continuation statements from rule 1.
Example:
1: par/and do
2: await e;
3: emit f;
4: with
5: await f;
6: with
7: ...
8: emit e;
9: end
The emit e
in trail-3 (line 8) starts an internal reaction that awakes the await e
in trail-1 (line 2).  Trail-2 terminates and the emit f
resumes in trail-1. Trail-1 terminates and the emit e
resumes in trail-3. Trail-3 terminates. Finally, the par/and
rejoins (all trails have terminated) and the program terminates.
Céu uses an abstraction mechanism that reconciles data and control state into the single concept of an organism. Organisms provide an object-like interface (data state) as well as multiple lines of execution (control state).
A class of organisms is composed of an interface and a single execution body. The interface exposes public variables, methods, and internal events, just like objects. The body can contain any valid code in Céu, which starts on the organism instantiation and executes in parallel with the program. Organism instantiation can be either static or dynamic.
The example below (in the right) blinks two LEDs in parallel with different frequencies. Each blinking LED is a static instance organism of the Blink
class:
|
|
The Blink
class (lines 1-11) exposes the led
and freq
fields, which correspond to the LED port and blinking frequency to be configured for each instance. The application creates two instances, specifying the fields in the constructors (lines 13-16 and 18-21). A constructor starts the instance body to execute in parallel with the application. When reaching the await 1min
(line 23), each instance already has its body switching between _on()
and _off()
every freq
milliseconds (lines 5-10).
The code in the left is semantically equivalent to the one in the right, which expands the organisms bodies (lines 13-18 and 22-27) in a par/or
with the rest of the application (await 1min
, in line 30). Note the await FOREVER
statements (lines 19 and 28) that avoid the organisms bodies to terminate the par/or
. The _Blink
type corresponds to a simple datatype without execution body (i.e., conventional structs or records or objects).
See also Organism declarations, Class and Interface declarations, and Organisms instantiation.
Keywords in Céu are reserved names that cannot be used as identifiers (e.g., variable and class names):
and async async/thread atomic await
bool break byte call call/rec
char class continue data do
else else/if emit end escape
event every f32 f64 false
finalize float FOREVER function global
if in input input/output int
interface interrupt kill loop native
native/pre new not nothing null
or outer output output/input par
par/and par/or pause/if pool pre
return s16 s32 s64 s8
request sizeof spawn sync tag
then this traverse true u16
u32 u64 u8 uint until
var void watching with word
@const @hold @nohold @plain @pure
@rec @safe
Céu uses identifiers to refer to variables, internal events, external events, classes/interfaces, data types, data tags, fields, and native symbols.
ID ::= +
ID_var ::= `_´ | ID // [variables and internal events] beginning with a lowercase letter
ID_ext ::= ID // [external events] all in uppercase, not beginning with a digit
ID_cls ::= ID // [classes and interfaces] beginning with an uppercase letter
ID_data ::= ID // [data types] beginning with an uppercase letter
ID_tag ::= ID // [data tags] all in uppercase, not beginning with a digit
ID_field ::= ID // [fields] not beginning with a digit
ID_nat ::= ID // [native symbols] beginning with an underscore
ID_type ::= ( ID_nat | ID_cls // [types]
| bool | byte | char | f32 | f64 |
| float | int | s16 | s32 | s64 |
| s8 | u16 | u32 | u64 | u8 |
| uint | void | word )
Class, interface, and data declarations create new types which can be used as type identifiers.
Examples:
var int a; // "a" is a variable, "int" is a type
emit e; // "e" is an internal event
await E; // "E" is an external input event
var Sprite s; // "Sprite" is a class and a type
var List l; // "List" is a data type and a type
return list.CONS.head; // "CONS" is a tag, "head" is a field
_printf("hello world!\n"); // "_printf" is a native symbol
Boolean types have the values true
and false
.
Integer values can be written in different bases and also as ASCII characters:
TODO: "1e10"
Examples:
// all following are equal to the decimal 127
v = 127;
v = 0777;
v = 0x7F;
// newline ASCII character = decimal 10
c = '\n';
TODO (like C)
The null
literal represents null pointers.
A sequence of characters surrounded by "
is converted into a null-terminated string, just like in C:
Example:
_printf("Hello World!\n");
Céu provides C-style comments.
Single-line comments begin with //
and run to end of the line.
Multi-line comments use /*
and */
as delimiters. Multi-line comments can be nested by using a different number of *
as delimiters.
Examples:
var int a; // this is a single-line comment
/** comments a block that contains comments
var int a;
/* this is a nested multi-line comment
a = 1;
*/
**/
Céu is statically typed, requiring all variables and events to be declared before they are used.
A type is composed of an identifier with a sequence of optional modifiers:
Type ::= ID_type ( `&&´ | `&´ | `?´ | `[´ [NUM] `]´ )
A type identifier can be a native identifier, a class identifier, a data type identifier or one of the primitive types:
ID_type ::= ( ID_nat | ID_cls | ID_data
bool | byte | char | f32 | f64 |
float | int | s16 | s32 | s64 |
s8 | u16 | u32 | u64 | u8 |
uint | void | word )
Examples:
var u8 v; // "v" is of 8-bit unsigned integer type
var _rect r; // "r" is of external native type "rect"
var char&& buf; // "buf" is a pointer to a "char"
var Send s; // "s" is an organism of class "Send"
var Tree t; // "t" is a data of type "Tree"
Céu has the following primitive types:
void // void type
word // type with the size of platform dependent word
bool // boolean type
char // char type
byte // 1-byte type
int uint // platform dependent signed and unsigned integer
s8 u8 // signed and unsigned 8-bit integer
s16 u16 // signed and unsigned 16-bit integer
s32 u32 // signed and unsigned 32-bit integer
s64 u64 // signed and unsigned 64-bit integer
float // platform dependent float
f32 f64 // 32-bit and 64-bit floats
See also the literals for these types.
Types defined externally in C can be prefixed by _
to be used in Céu programs.
Example:
var _message_t msg; // "message_t" is a C type defined in an external library
Native types support annotations which provide additional information to the compiler.
TODO (brief description)
Types can be suffixed with the following modifiers: &
, &&
, ?
, and [N]
.
TODO
Céu supports two forms of references: aliases and pointers.
TODO (like C++ references)
TODO (like C)
restrictions - across yielding statements
TODO (like Maybe)
TODO (vectors, pools)
One-dimensional vectors are declared by suffixing the variable type with the vector length surrounded by [
and ]
. The first index of a vector is zero.
Example:
var int[2] v; // declares a vector "v" of 2 integers
A block is a sequence of statements separated by semicolons (;
):
Block ::= { Stmt `;´ }
Note: statements terminated with the end
keyword do not require a terminating semicolon.
A block creates a new scope for variables, which are only visible for statements inside the block.
Compound statements (e.g. if-then-else) create new blocks and can be nested for an arbitrary level.
A block can be explicitly created with the do-end
statement:
Do ::= do Block end
TODO ("static code" appended in sequence to the beginning)
Pre ::= pre do Block end
nothing
is a innocuous statement:
Nothing ::= nothing
The syntax for the definition of variables is as follows:
DclVar ::= var Type ID_var [`=´ Assignment] { `,´ ID_var [`=´ Assignment] }
A variable has an associated type and can be optionally initialized (see Assignments).
Variables are only visible inside the block they are defined.
Examples:
var int a=0, b=3; // declares and initializes integer variables "a" and "b"
var int[2] v; // declares a vector "v" of size 2
An organism is a variable whose type is the identifier of a class declaration. An optional constructor can initialize the organism fields:
DclOrg ::= var Type ID_var [ with
Block
end ]
Example:
class T with
var int v;
do

end
var T t with // "t" is an organism of class "T"
this.v = 0; // whose field "v" is initialized to "0"
end
After the declaration, the body of an organism starts to execute in [parallel](#parallel-compositions] with the rest of the application. The table below shows the equivalent expansion of an organism declaration to a par/or
containing the class body:
|
|
Given that an organism is a variable, the block it is declared restricts its lifetime. In the expansion, the par/or
makes the organism to go out of scope when
terminates.
TODO (assumes code-pos-declaration closes the block exactly on the end)
TODO (vectors of organisms: copy the declaration N times)
Inside constructors the expression this
refers to the new organism, while the expression outer
refers to the enclosing organism creating the new organism:
class U with
var int v;
do
...
end
class T with
var int v;
do
var U u with
this.v = outer.v; // "this" is of class "U", "outer" is of class "T"
end;
end
A pool is a container for dynamic instances of organisms and recursive data of the same type:
DclPool ::= pool Type ID_var [`=´ Assignment] { `,´ ID_var [`=´ Assignment] }
The type has to be a class, interface, or data type identifier followed by a dimension modifier. For pools of classes and recursive data types, the number inside the dimension brackets represents the maximum number of instances supported by the pool. For pools of interfaces, the number represents the maximum number of bytes for all instances (as each instance may have a different size).
The number inside the vector modifier brackets is optional. If not specified, the number of instances in the pool is unbounded and all allocations go to the heap. When specified, allocation goes to a static memory pool preallocated at compile time.
Examples:
pool T[10] ts; // a pool of at most 10 instances of class "T"
pool T[] ts; // an unbounded pool of instances of class "T"
pool I[100] is; // a pool of at most 100 bytes of instances of interface "I"
pool I[] is; // an unbounded pool of instances of interface "I"
pool D[100] ds; // a pool of at most 100 instances of recursive data type "D"
pool D[] ds; // an unbounded pool of instances of recursive data type "D"
The lifetime of all instances inside a pool is restricted to the block it is declared. When a pool of organisms goes out of scope, all organism bodies are automatically aborted.
See Dynamic execution for organisms allocation. See TODO for recursive data allocation.
TODO (intro/prototype/implementation)
/* internal functions */
DclFun ::= function [@rec] `(´ParList`)´ `=>´ Type ID_var
[ `do´ Block `end´ ]
/* external functions */
DclFunExt ::= output [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
| input [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
[ `do´ Block `end´ ]
Return ::= return [Exp]
ParList ::= ParItem { `,´ ParItem }
ParItem ::= [@hold] Type [ID_var]
TODO (like functions in any language)
TODO (more or less like dynamically loaded functions)
TODO (like return in any language)
TODO
DclIsr ::= interrupt `[´ NUM `]´ [@rec]
[ `do´ Block `end´ ]
See also Event handling.
Internal events have the same purpose of external events, but for communication within trails in a program.
The declaration of internal events is as follows:
DclInt ::= event (Type | `(´ TypeList `)´) ID_var { `,´ ID_var }
In contrast with external events, an internal event is for input and output at the same time.
Internal events cannot be of a vector type.
Note: void is a valid type for signal-only internal events.
External events are used as interfaces between programs and devices from the real world:
Being reactive, programs in Céu have input events as their sole entry points through await statements.
The declaration of input and output events is as follows:
DclExt ::= output (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
| input (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
TypeList ::= Type { `,´ Type }
Events communicate values between the environment and the application (and vice-versa). The declaration includes the type of the value, which can be also a list of types when the event communicates multiple values.
Note: void
is a valid type for signal-only events.
The visibility of external events is always global, regardless of the block they are declared.
Examples:
input void A,B; // "A" and "B" are input events carrying no values
output int MY_EVT; // "MY_EVT" is an output event carrying integer values
The availability of external events depends on the platform in use. Therefore, external declarations just make pre-existing events visible to a program.
Refer to Environment for information about interfacing with external events in the platform level.
TODO (emit + await)
DclReq ::= output/input `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
| input/output `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
[ `do´ Block `end´ ]
A class
is a template for creating organisms. It contains an interface and a body common to all instances of the class. The interface exposes internal variables, events, and methods that other organisms can manipulate directly. The body specifies the behavior of the organism and executes when it is instantiated.
An interface
is a template for classes that shares the same interface1. The body and method implementations may vary among classes sharing the same interface.
(1 The term "interface" is overload with two possible meanings: the set of members exposed by a class; and a template that defines a set of members that classes can reuse.)
The declaration of classes and interfaces is as follows:
DclCls ::= class ID_cls with
Dcls // interface
do
Block // body
end
DclIfc ::= interface ID_cls with
Dcls // interface
end
Dcls ::= { (DclVar | DclInt | DclPool | DclFun | DclImp) `;´ }
DclImp ::= interface ID_cls { `,´ ID_cls }
Dcls
is a sequence of variables, events, pools, and functions (methods) declarations. It can also refer to other interfaces through a DclImp
clause, which copies all declarations from the referred interfaces.
TODO
DclData ::= data ID_data with
(Struct | Union)
end
Struct ::= DclVar `;´ { DclVar `;´ }
Union ::= DclTag { or DclTag }
DclVar ::= var Type ID_var { `,´ ID_var }
DclTag ::= tag ID_tag with
DclVar `;´ { DclVar `;´ }
end
Example (structured data type)
data Foo with
var u8 a;
var int b;
var s16 c;
end
Example (tagged data type)
data Foo with
// declare 'BAR' as one possible structure of 'Foo'
tag BAR with
var u8 a;
var int b;
var s16 c;
end
or
// declare 'BAZ' as another possible structure of 'Foo'
tag BAZ with
var int d;
var s8 e;
end
end
Note: Céu vectors are not yet supported within data types!
TODO (native/pre)
Native blocks define new types, variables, and functions in C:
Native ::= (native | native/pre) do
<code_in_C>
end
Example:
native do
#include
int inc (int i) {
return i+1;
}
end
_assert(_inc(0) == 1);
If the code in C contains the terminating end
keyword of Céu, the native
block should be delimited with any matching comments to avoid confusing the parser:
native do
/*** c code ***/
char str = "This `end` confuses the parser";
/*** c code ***/
end
Native declarations provide additional information about external C symbols. A declaration is an annotation followed by a list of symbols:
DclNat ::= native [@pure|@const|@nohold|@plain] Nat_list
Nat_list ::= (Nat_type|Nat_func|Nat_var) { `,` (Nat_type|Nat_func|Nat_var) }
Nat_type ::= ID_nat `=´ NUM
Nat_func ::= ID_nat `(´ `)´
Nat_var ::= ID_nat
A type declaration may define its size in bytes to help the compiler organizing memory. A type of size 0
is an opaque type and cannot be instantiated as a variable that is not a pointer.
Functions and variables are distinguished by the ()
that follows function declarations.
Native symbols can have the following annotations:
@plain states that the type is not a pointer to another type. @const states that the symbol is a constant (e.g. a #define
). @pure states that the function has no side effects. @nohold states that the function does not hold pointers passed as parameters.
The static analysis of Céu relies on annotations.
Examples:
native _char=1, _FILE=0; // "char" is a 1-byte type, while `FILE` is "opaque"
native @plain _rect; // "rect" is not a pointer type
native @const _NULL; // "NULL" is a constant
native @pure _abs(), _pow(); // "abs" and "pow" are pure functions
native @nohold _fprintf(), _sprintf(); // functions receive pointers but do not hold references to them
A variable or function can be declared as @safe
with a set of other functions or variables:
DclDet ::= @safe ID with ID { `,´ ID }
Example:
native _p, _f1(), _f2();
@safe _f1 with _f2;
var int* p;
@safe p with _p;
par do
_f1(...); // `f1` is safe with `f2`
*p = 1; // `p` is safe with `_p`
...
with
_f2(...); // `f2` is safe with `f1`
*_p = 2; // `_p` is safe with `p`
...
end
See also Static analysis.
Céu supports many kinds of assignments:
Set ::= (Exp | `(´VarList`)´) `=´ Assignment
VarList ::= ID_var { `,´ ID_var } `)´
Assignment ::= Exp
| AssignableBlock
| <await>
| ( [ `(´ ] <emit-ext>
| <call-ext>
| <request-ext>
[ `)´ ] )
| [ `new´ ] Data
| <traverse-loop>
| <traverse-rec>
| Vector
| <lua>
| <do-org>
| <spawn>
| <thread>
The expression on the left side must be assignable.
TODO (Exp, VarList)
The simpler form of assignment uses expressions as values.
Example:
var int a,b;
a = b + 1;
A whole block can be used as an assignment value by escaping from it. The following block statements can be used in assignments: do-end
if-then-else
, loop
, every
, and par
:
AssignableBlock ::= <do-end> | <if-then-else> | <loop> | <every> | <par>
An escape
statement escapes the deepest block being assigned to a variable. The expression following it is then assigned to the respective variable:
Escape ::= escape Exp
Every possible path inside the block must reach a escape
statement whose expression becomes the final value of the assignment.
Example:
a = loop do // a=1, when "cond" is satisfied
...
if cond then
escape 1; // "loop" is the deepest assignment block
end
...
end
Every program in Céu contains an implicit do-end
surrounding it, assigning to a special integer variable $ret
holding the return value for the program execution.
Therefore, a program such as
escape 1;
should read as
var int $ret =
do
escape 1;
end;
See Await statements.
See Emit statements.
TODO
Data ::= ID_data [`.´ ID_tag] `(´ List `)´
List ::= [ (Data|Exp) { `,´ (Data|Exp) } ]
Example (structured data type)
// calls the constructor for 'Foo' and uses the provided values for struct initialization
var Foo f = Foo(4, 7, 1);
Example (tagged data type)
// calls the constructor for 'Foo' (using tag BAZ) and uses the provided values for struct initialization
var Foo f = Foo.BAZ(2, -9);
TODO
TODO
Vector ::= Item { `..´ Item }
Item ::= Exp | `[´ [ExpList] `]´
Example
var int[3] v; // declare an empty vector of length 3
v = v .. [8]; // append value '8' to the empty vector
v = v .. [1] .. [5]; // append the values '1' and '5' to the vector
// here: v = {8, 1, 5}
TODO
TODO
See Spawn.
See Threads.
The syntax for function calls is as follows:
/* internal calls */
CallInt ::= [call|call/rec] Exp * `(´ [ExpList] `)´
/* external calls */
CallExt ::= (call+call/rec) ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
ExpList = Exp { `,´ Exp }
TODO
TODO
Events are the most fundamental concept of Céu, accounting for its reactive nature. Programs manipulate events through the await
and emit
statements. An await
halts the running trail until that event occurs. An event occurrence is broadcast to all trails trails awaiting that event, awaking them to resume execution.
Céu supports external and internal events. External events are triggered by the environment, while internal events, by the emit
statement. See also Synchronous execution model for the differences between external and internal reactions.
The await
statement halts the running trail until the referred wall-clock time, input event, or internal event occurs.
Await ::= ( await ID_ext |
await Exp |
await (WCLOCKK|WCLOCKE)
) [ until Exp ]
| await FOREVER
WCLOCKK ::= [NUM h] [NUM min] [NUM s] [NUM ms] [NUM us]
WCLOCKE ::= `(´ Exp `)´ (h|min|s|ms|us)
Examples:
await A; // awaits the input event `A`
await a; // awaits the internal event `a`
await 10min3s5ms100us; // awaits the specified time
await (t)ms; // awaits the current value of the variable `t` in milliseconds
await FOREVER; // awaits forever
An await
may evaluate to zero or more values which can be captured with the optional assignment syntax.
The optional until
clause tests an additional condition required to awake. It can be understood as the expansion below:
loop do
await <...>;
if <Exp> then
break;
end
end
For await statements with internal or external events, the running trail awakes when the referred event is emitted. The await
evaluates to the type of the event.
input int E;
var int v = await E;
event (int,int*) e;
var int v;
var int* ptr;
(v,ptr) = await e;
TODO (awake rule for internal events, unless "every")
For await statements with wall-clock time (i.e., time measured in minutes, milliseconds, etc.), the running trail awakes when the referred time elapses.
A constant time is expressed with a sequence of value/unit-of-time pairs (see WCLOCKK
above). An expression time is specified with an expression in parenthesis followed by a single unit of time (see WCLOCKE
above).
The await
evaluates to the residual delta time (dt) (i.e. elapsed time minus requested time), measured in microseconds:
var int dt = await 30ms; // if 31ms elapses, then dt=1000
Note: dt
is always greater than or equal to 0.
TODO
The await FOREVER
halts the running trail forever. It cannot be used in assignments, because it never evaluates to anything.
The emit
statement triggers the referred wall-clock time, input event, or internal event, awaking all trails waiting for it.
Emit ::= emit Exp [ `=>´ (Exp | `(´ [ExpList] `)´)
| emit ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
| emit (WCLOCKK|WCLOCKE)
Emit statements with internal or external events expect parameters that match the event type (unless the event is of type void
).
Examples:
output int E;
emit E => 1;
event (int,int) e;
emit e => (1,2);
External input events can only be emitted inside asynchronous blocks.
The emission of internal events start new internal reactions.
TODO (emit output evaluates to "int")
Emit statements with wall-clock time expect expressions with units of time, as described in Await time.
Like input events, time can only be emitted inside asynchronous blocks.
TODO (emit+await)
Request ::= request ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
TODO
DoOrg ::= do ID_cls [with
Constructor
end]
The spawn
statement creates instances of organisms dynamically:
Spawn ::= spawn ID_cls [in Exp] [with
Constructor
end]
TODO(option return)
The optional in
clause allows the statement to specify in which pool the organisms will live. If absent, the organism is allocated on an implicit pool in the outermost block of the class the allocation happens.
On allocation, the body of the organism starts to execute in parallel with the rest of the application, just like static organisms. The constructor clause is also the same as for static organisms.
In contrast to static organisms, the lifetime of a dynamic instance is attached to the scope of the pool and not to the scope of the spawn
instantiation. Furthermore, a dynamic organism is automatically deallocated when its execution body terminates.
See Static analysis for the restrictions on manipulating pointers and references to organisms.
TODO
kill * Exp * [ `=>´ Exp ]
Conditional flow uses the if-then-else
statement:
If ::= if Exp then
Block
{ else/if Exp then
Block }
[ else
Block ]
end
The block following then
executes if the condition expression after the if
evaluates to a non-zero value. Otherwise, the same process holds each else/if
alternative. Finally, it they all fail, the block following the else
executes.
A loop
continuously executes its body block:
Loop ::= loop[`/´ Exp] [ ID_var [in Exp] ] do
Block
end
A loop
terminates when it reaches a break
or its (optional) iterator terminates.
TODO (hard limit)
A break
escapes the innermost enclosing loop:
Break ::= break
Example:
loop do // loop 1
...
loop do // loop 2
if <cond-1> then
break; // escapes loop 2
end
...
end
...
if <cond-2> then
break; // escapes loop 1
end
...
end
A continue
restarts the innermost enclosing loop:
Continue ::= continue
Example:
loop do // loop 1
...
loop do // loop 2
if <cond-1> then
continue; // restarts loop 2
end
...
end
...
if <cond-2> then
break; // restarts loop 1
end
...
end
A continue
can only be used inside an if-then-else
with an empty else
branch and exactly one level deeper than the enclosing loop
:
loop do
par do // makes the "continue" illegal
if <cond> then
continue;
else // makes the "continue" illegal
...
end
with
...
end
end
A loop
may specify an iterator that yields a new value on each loop iteration.
For iterators in which Exp
is empty or is of type int
, ID_var
is incremented after each loop iteration. ID_var
is automatically declared read-only, with visibility restricted to the loop body, and is initialized to zero. The optional Exp
limits the number of iterations, and is evaluated once before the loop starts.
Example:
loop i in 10 do
_printf("i = %d\n", i); // prints "i = 0" up to "i = 9"
end
For iterators in which Exp
evaluates to a pool of organisms, ID_var
evaluates to pointers to instances in the pool, one at a time, from the oldest to the newest created. ID_var
is automatically declared read-only, with visibility restricted to the loop body.
TODO (example)
The every
statement continuously awaits an event and executes its body:
Every ::= every (Var | `(´VarList`)´) in (WCLOCKK|WCLOCKE|ID_ext|Exp) do
Block
end
An every
expands to a loop
as illustrated below:
|
|
The body of an every
cannot contain an await
, ensuring that no occurrences of <event>
are ever missed.
TODO (restrictions, escape/break)
TODO (exception to the rule for internal events)
TODO
TraverseLoop ::= traverse ID_var in (`[´ Exp `]´ | Exp)
[ with Dcls end ]
do
Block
end
TraverseRec ::= traverse['/' NUM] Exp
[ with Block end ]
The finalize
statement postpones the execution of its body to happen when its associated block goes out of scope:
Finalize ::= finalize
[Exp `=´ Assignment]
with
Block
end
The presence of the optional attribution clause determines which block to associate with the finalize
:
Example:
input int A;
par/or do
var _FILE* f;
finalize
f = _fopen("/tmp/test.txt");
with
_fclose(f);
end
every v in A do
fwrite(&v, ..., f);
end
with
await 1s;
end
The program opens f
and writes to it on every occurrence of A
. The writing trail is aborted after one second, but the finalize
safely closes the file, because it is associated to the block that declares f
.
The static analysis of Céu enforces the use of finalize
for unsafe attributions.
The parallel statements par/and
, par/or
, and par
split the running trail in multiple others:
Pars ::= (par/and|par/or|par) do
Block
with
Block
{ with
Block }
end
They differ only on how trails terminate (rejoin).
See Synchronous execution model for a detailed description of parallel execution.
The par/and
statement stands for parallel-and and rejoins when all trails terminate:
The par/or
statement stands for parallel-or and rejoins when any of the trails terminate:
The par
statement never rejoins and should be used when the trails in parallel are supposed to run forever:
The watching
statement aborts its body when its associated event occurs:
Watching ::= watching [ (Var | `(´VarList`)´) in ] (WCLOCKK|WCLOCKE|ID_ext|Exp)
Block
end
A watching
expands to a par/or
as illustrated below:
|
|
TODO (Var/VarList is implicitly declared)
TODO: strong abortion
TODO: see Await for supported events
TODO
Pause ::= pause/if Exp do
Block
end
Asynchronous execution permit that programs execute time consuming computations without interfering with the synchronous side of applications (i.e., everything, except asynchronous statements).
Async ::= (async | async/thread) [ `(´VarList`)´ ] do
Block
end
Asynchronous blocks (async
) are the simplest alternative for asynchronous execution.
An async
body can contain non-awaiting loops (tight loops), which are disallowed on the synchronous side to ensure that programs remain reactive.
The optional list of variables copies values between the synchronous and asynchronous scopes. With the prefix &
, the variable is passed by reference and can be altered from inside the async
.
The next example uses an async
to execute a time-consuming computation, keeping the synchronous side reactive.  The example prints the v = <v+i>
message exactly 103 times.
TODO(async/thread)
TODO
Sync ::= sync do
Block
end
TODO(mutual exclusion isr and sync)
Atomic ::= atomic do
Block
end
TODO
C ::= `{´ <C code> `}´
TODO
Lua ::= `[´ {`=´} `[´
{ <lua code> | `@´ Exp }
`]´ {`=´} `]´
The syntax for expressions in Céu is as follows:
Exp ::= Prim
| Exp or Exp
| Exp and Exp
| Exp (`!=´|`==´|`<=´|`<´|`>´|`>=´) Exp
| Exp `|´ Exp
| Exp `^´ Exp
| Exp `&´ Exp
| Exp (`<<´|`>>´) Exp
| Exp (`+´|`-´) Exp
| Exp (`*´|`/´|`%´) Exp
| (not|`+´|`-´|`~´|`*´|`&&´|`&´|`$$´|`$´) Exp
| `(´ Type `)´ Exp /* same precedence as previous */
| Exp `[´ Exp `]´ /* same precedence for all following */
| Exp (`.´|`:´) (ID_field | ID_tag)
| Exp (`?´|`!´)
| Exp `(´ [ExpList] `)´ [finalize with Block end]
Prim ::= `(´ Exp `)´
| sizeof `(´ (Type|Exp) `)´
| ID_var | ID_nat
| null | NUM | String
| true | false
| global | this | outer
| (call | call/rec) Exp
| <c-stat>
Note: assignments are not expressions in Céu.
TODO: global, this, outer, ID_var, ID_nat, null, NUM, String, true, false, call/call/rec/finalize, C, parens
The arithmetic operators of Céu are
+ - % * / + -
which correspond to addition, subtraction, modulo (remainder), multiplication, division, unary-plus, and unary-minus.
The relational operators of Céu are
== != > < >= <=
which correspond to equal-to, not-equal-to, greater-than, less-than, greater-than-or-equal-to, and less-than-or-equal-to.
Relational expressions evaluate to 1 (true) or 0 (false).
The logical operators of Céu are
not and or
The bitwise operators of Céu are
~ & | ^ << >>
which correspond to not, and, or, xor, left-shift, and right-shift.
Céu uses square brackets to index vectors:
Index ::= Exp `[´ Exp `]´
The expression on the left side is expected to evaluate to a vector.
Vector indexes start at zero.
TODO
TODO
Alias ::= `&´ Exp
The operand to &
must be an [[#sec.exps.assignable|assignable expression]].
TODO
The operator &&
returns the address of its operand, while the operator *
dereferences its pointer operand.
Address ::= `&&´ Exp
Deref ::= `*´ Exp
The operand to &&
must be an [[#sec.exps.assignable|assignable expression]].
TODO (tags,fields)
The operators .´ and
:´ access the fields of structs.
Dot ::= Exp `.´ Exp
Colon ::= Exp `:´ Exp
The operator .
expects a struct
as its left operand, while the operator :
expects a reference to a struct
.
Example:
native do
typedef struct {
int v;
} mystruct;
end
var _mystruct s;
var _mystruct* p = &s;
s.v = 1;
p:v = 0;
Note: struct
must be declared in C, as Céu currently has no support for it.
TODO
TODO (index clash)
TODO (?!)
Céu uses parenthesis for type casting:
Cast ::= `(´ ID_type `)´
A sizeof
expression returns the size of a type or expression, in bytes:
Sizeof ::= sizeof `(´ (Type|Exp) `)´
Céu follows the same precedence of C operators:
/* lowest priority */
or
and
!= == <= >= < >
|
^
&
>> <<
+ -
* / %
not + - ~ * && & $$ $ (Type)
() [] : . ? !
/* highest priority */
An assignable expression (also known as an l-value) can be a variable, vector index, pointer dereference, or struct access. L-values are required in [[#sec.stmts.assignments|assignments]] and [[#sec.exps.pointers|references]].
Examples:
var int a;
a = 1;
var int[2] v;
v[0] = 1;
var int&& p;
*p = 1;
var _mystruct s;
s.v = 1;
var _mystruct&& ps;
ps:v = 1;
TODO (introduction)
TODO (weakly typed, like C)
TODO (index clash)
TODO
TODO
TODO (index clash)
TODO
As a reactive language, Céu depends on an external environment (the host platform) to provide input and output events to programs. The environment is responsible for sensing the world and notifying Céu about changes. The actual events vary from environment to environment, as well as the implementation for the notification mechanism (e.g. polling or interrupt-driven).
The final output of the compiler of Céu is a program in C that follows a standard application programming interface. The interface specifies some types, macros, and functions, which the environment has to manipulate in order to guide the execution of the original program in Céu.
The example below illustrates a possible main
for a host platform:
#include "_ceu_app.c"
int main (void)
{
char mem[sizeof(CEU_Main)];
tceu_app app;
app.data = &mem;
ceu_app_init(&app);
while(app->isAlive) {
ceu_sys_go(app, CEU_IN__ASYNC, CEU_EVTP((void*)NULL));
ceu_sys_go(app, CEU_IN__WCLOCK, CEU_EVTP(<how-much-time-since-previous-iteration>));
if (occuring(CEU_IN_EVT1)) {
ceu_sys_go(app, CEU_IN__EVT1, param1);
}
...
if (occuring(CEU_IN_EVTn)) {
ceu_sys_go(app, CEU_IN__EVTn, paramN);
}
}
return app->ret;
}
int occurring (int evt_id) {
<platform dependent>
}
tceu_app
is a type that represents an application in Céu. The field app.data
expects a pointer to the memory of the application, which has to be previously declared.
TODO
TODO
TODO (index clash)
TODO
TODO (index clash)
TODO
TODO
Céu provides a command line compiler that generates C code for a given input program. The compiler is independent of the target platform.
The generated C output should be included in the main application, and is supposed to be integrated with the specific platform through the presented [[#sec.env.api|API]].
The command line options for the compiler are as follows:
./ceu <filename> # Ceu input file, or `-` for stdin
--output <filename> # C output file (stdout)
--defs-file <filename> # define constants in a separate output file (no)
--join (--no-join) # join lines enclosed by /*{-{*/ and /*}-}*/ (join)
--dfa (--no-dfa) # perform DFA analysis (no-dfa)
--dfa-viz (--no-dfa-viz) # generate DFA graph (no-dfa-viz)
--m4 (--no-m4) # preprocess the input with `m4` (no-m4)
--m4-args # preprocess the input with `m4` passing arguments in between `"` (no)
The values in parenthesis show the defaults for the options that are omitted.
Use of the unsafe operator ":=" for non-pointer attributions.
Instead, use =
.
Example:
var int v := 1;
>>> ERR [1101] : file.ceu : line 1 : wrong operator
Use of finalize
for non-pointer attributions.
Instead, do not use finalize
.
Example:
var int v;
finalize
v = 1;
with
<...>
end
>>> ERR [1102] : file.lua : line 3 : attribution does not require "finalize"
Use of the unsafe operator :=
for constant pointer attributions.
Instead, use =
.
Example:
var int ptr := null;
>>> ERR [1103] : file.ceu : line 1 : wrong operator
Use of finalize
for constant pointer attributions.
Instead, do not use finalize
.
Example:
var int ptr;
finalize
ptr = null;
with
<...>
end
>>> ERR [1104] : file.lua : line 3 : attribution does not require `finalize´
Use of normal pointer *
to hold pointer to acquired resource.
Instead, use []
.
Example:
var int* ptr = _malloc();
>>> ERR [1105] : file.ceu : line 1 : destination pointer must be declared with the `[]´ buffer modifier
Omit @hold
annotation for function parameter held in the class or global.
Instead, annotate the parameter declaration with @hold
.
Examples:
class T with
var void* ptr;
function (void* v)=>void f;
do
function (void* v)=>void f do
ptr := v;
end
end
>>> ERR [1106] : file.ceu : line 6 : parameter must be `hold´
/*****************************************************************************/
native do
void* V;
end
function (void* v)=>void f do
_V := v;
end
>>> ERR [1106] : file.ceu : line 5 : parameter must be `hold´
Access to pointer across an await
statement. The pointed data may go out of scope between reactions to events.
Instead, don't do it. :)
(Or check if the pointer is better represented as a buffer pointer ([]
).)
Examples:
event int* e;
var int* ptr = await e;
await e; // while here, what "ptr" points may go out of scope
escape *ptr;
>>> ERR [1107] : file.ceu : line 4 : pointer access across `await´
/*****************************************************************************/
var int* ptr = <...>;
par/and do
await 1s; // while here, what "ptr" points may go out of scope
with
event int* e;
ptr = await e;
end
escape *ptr;
>>> ERR [1107] : file.ceu : line 8 : pointer access across `await´
Use of finalize
inside constructor.
Instead, move it to before the constructor or to inside the class.
Examples:
class T with
var void* ptr;
do
<...>
end
var T t with
finalize
this.ptr = _malloc(10);
with
_free(this.ptr);
end
end;
>>> ERR [1008] : file.ceu : line 7 : `finalize´ inside constructor
/*****************************************************************************/
class T with
var void* ptr;
do
<...>
end
spawn T with
finalize
this.ptr = _malloc(10);
with
_free(this.ptr);
end
end;
>>> ERR [1008] : file.ceu : line 7 : `finalize´ inside constructor
Call missing finalize
clause.
Call passes a pointer. Function may hold the pointer indefinitely. Pointed data goes out of scope and yields a dangling pointer.
Instead, finalize
the call.
Example:
var char[255] buf;
_enqueue(buf);
>>> ERR [1009] : file.ceu : line 2 : call requires `finalize´'
Call a function that does not require a finalize
.
Instead, don't use it.
Example:
_f() finalize with
<...>
end;
>>> ERR [1010] : file.ceu : line 1 : invalid `finalize´
Stmt ::= <empty-string>
| nothing
| escape Exp
| return [Exp]
| break
| continue
/* Declarations */
/* variables, organisms, pools, and internal events */
| var Type ID_var [`=´ <Assignment>] { `,´ ID_var [`=´ <Assignment>] }
| var Type ID_var with
Block
end
| pool Type ID_var [`=´ <Assignment>] { `,´ ID_var [`=´ <Assignment>] }
| event (Type | `(´ TypeList `)´) ID_var { `,´ ID_var }
/* internal functions */
| function [@rec] `(´ParList`)´ `=>´ Type ID_var
[ `do´ Block `end´ ]
/* external functions */
| output [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
| input [@rec] `(´ParList`)´ `=>´ Type ID_var ID_ext { `,´ ID_ext }
[ `do´ Block `end´ ]
/* interrupts */
| interrupt `[´ NUM `]´ [@rec]
[ `do´ Block `end´ ]
/* external events */
| output (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
| input (Type | `(´ TypeList `)´) ID_ext { `,´ ID_ext }
/* external requests */
| output/input `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
| input/output `[´ [Exp] `]´ `(´ParList`)´ `=>´ Type ID_ext { `,´ ID_ext }
[ `do´ Block `end´ ]
/* classes & interfaces */
| class ID_cls with
Dcls
do
Block
end
| interface ID_cls with
Dcls
end
where
Dcls ::= { (<var> | <event-int> | <pool> | <function> | DclImp) `;´ }
DclImp ::= interface ID_cls { `,´ ID_cls }
/* data types */
| data ID_data with
(Struct | Union)
end
where
Struct ::= DclVar `;´ { DclVar `;´ }
Union ::= DclTag { or DclTag }
where
DclVar ::= var Type ID_var { `,´ ID_var }
DclTag ::= tag ID_tag with
DclVar `;´ { DclVar `;´ }
end
/* C integration */
| native [@pure|@const|@nohold|@plain] Nat_list
where
Nat_list ::= (Nat_type|Nat_func|Nat_var) { `,` (Nat_type|Nat_func|Nat_var) }
Nat_type ::= ID_nat `=´ NUM
Nat_func ::= ID_nat `(´ `)´
Nat_var ::= ID_nat
| (native/pre | native) do
<C code definitions>
end
/* deterministic annotations */
| @safe ID with ID { `,´ ID }
/* Assignments */
| (Exp | `(´VarList`)´) `=´
/* Assignment */
( Exp
| AssignableBlock
| <await>
| ( [ `(´ ] <emit-ext>
| <call-ext>
| <request-ext>
[ `)´ ] )
| [ `new´ ] Data
| <traverse-loop>
| <traverse-rec>
| Vector
| <lua>
| <do-org>
| <spawn>
| <thread>
)
where
Data ::= ID_data [`.´ ID_tag] `(´ List `)´
List ::= [ (Data|Exp) { `,´ (Data|Exp) } ]
Vector ::= Item { `..´ Item }
Item ::= Exp | `[´ [ExpList] `]´
AssignableBlock ::= <do-end> | <if-then-else> | <loop> | <every> | <par>
/* Function calls */
/* internal calls */
| [call|call/rec] Exp * `(´ [ExpList] `)´
/* external calls */
| (call+call/rec) ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
/* Event handling */
/* internal/external await */
| ( await ID_ext
| await Exp
| await (WCLOCKK|WCLOCKE)
) [ until Exp ]
| await FOREVER
/* internal/external emit */
| emit Exp [ `=>´ (Exp | `(´ [ExpList] `)´)
| emit ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
| emit (WCLOCKK|WCLOCKE)
/* external request */
| request ID_ext [ `=>´ (Exp | `(´ [ExpList] `)´)
/* Organism instantiation */
/* do organism */
| do ID_cls with
Block
end
/* spawn */
| spawn * ID_cls * [in Exp]
[ with Block end ]
/* kill */
| kill * Exp * [ `=>´ Exp ]
/* Flow control */
/* explicit block */
| do Block end
/* pre (top level) execution */
| pre do
Block
end
/* conditional */
| if Exp then
Block
{ else/if Exp then
Block }
[ else
Block ]
end
/* loops */
| loop[`/´ Exp] [ ID_var [in Exp] ] do
Block
end
| every (Var | `(´VarList`)´) in (WCLOCKK|WCLOCKE|ID_ext|Exp) do
Block
end
/* traverse */
| traverse ID_var in (`[´ Exp `]´ | Exp)
[ with Dcls end ]
do
Block
end
| traverse['/' NUM] Exp
[ with Block end ]
/* finalization */
| finalize [<assignment>] with
Block
end
/* parallel compositions */
| (par/and|par/or|par) do
Block
with
Block
{ with
Block }
end
| watching [ (Var | `(´VarList`)´) in ] (WCLOCKK|WCLOCKE|ID_ext|Exp)
do
Block
end
/* pause */
| pause/if Exp do
Block
end
/* asynchronous execution */
| (async | [async/thread]) [ `(´VarList`)´ ] do
Block
end
/* synchronization */
| sync do
Block
end
| atomic do
Block
end
/* C integration */
| `{´ <C code> `}´
/* Lua integration */
| `[´ {`=´} `[´
{ <lua code> | `@´ Exp }
`]´ {`=´} `]´
/* Block */
Block ::= { Stmt `;´ }
/* Identifiers */
ID ::=  +
ID_var ::= `_´ | ID // beginning with a lowercase letter
ID_ext ::= ID // all in uppercase, not beginning with a digit
ID_cls ::= ID // beginning with an uppercase letter
ID_data ::= ID // beginning with an uppercase letter
ID_tag ::= ID // all in uppercase, not beginning with a digit
ID_field ::= ID // not beginning with a digit
ID_nat ::= ID // beginning with an underscore
ID_type ::= ( ID_nat | ID_cls | ID_data
| bool | byte | char | f32 | f64 |
| float | int | s16 | s32 | s64 |
| s8 | u16 | u32 | u64 | u8 |
| uint | void | word )
/* Types */
Type ::= ID_type ( `&&´ | `&´ | `?´ | `[´ [NUM] `]´ )
/* Lists */
TypeList ::= Type { `,´ Type }
ExpList ::= Exp { `,´ Exp }
VarList ::= ID_var { `,´ ID_var }
ParList ::= ParItem { `,´ ParItem }
where
ParItem ::= [@hold] Type [ID_var]
/* Wall-clock values */
WCLOCKK ::= [NUM h] [NUM min] [NUM s] [NUM ms] [NUM us]
WCLOCKE ::= `(´ Exp `)´ (h|min|s|ms|us)
/* Expressions */
Exp ::= Prim
| (`$$´|`$´) Exp
| Exp (`?´|`!´)
| Exp `(´ [ExpList] `)´ [finalize with Block end]
Prim ::= `(´ Exp `)´
| ID_var | ID_nat
| null | NUM | String
| true | false
| (call | call/rec) Exp
| <c-code>
/* Operator precedence */
/* lowest priority */
or
and
!= == <= >= < >
|
^
&
>> <<
+ -
* / %
not + - ~ * && & $$ $ (Type)
() [] : . ? !
/* highest priority */
/* Other */
// single-line comment
/** nested
/* multi-line */
comments **/
# preprocessor directive
Céu is distributed under the MIT license reproduced below:
Copyright (C) 2012 Francisco Sant'Anna
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
 IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


Best Practices and Tips
with Josh Holtz
Who is Josh Holtz?
-
Core contributor of fastlane since early 2015
-
Lead maintainer of fastlane since March 2018
-
Add features, manage issues, decide direction/focus
-
Currently spending to 20 to 30 hours a week maintaing fastlane
-
-
Owner of RokkinCat since 2011
-
Software consulting agency focused on new product development
-
Personally focused on mobile development and CI/CD
-
Return value of "Best Practices and Tips"?
-
Cleaner and more maintable code
-
Flexable and configurable
-
Easier to debug
-
Awareness of lesser known features
What will we cover?
-
1. Install with
Lock those gem versionsbundler
-
2. Platforms
Namespace platform specific lanes -
3. Lane Options and
Open up user input for lanesUI
-
4. Lane Description
Don't forget aboutdesc
-
5. Environment Variables
Minimize harcoding -
6. fastlane Documentation
It's there 🙃 -
7. Separate Apple ID
Pretend fastlane is a person -
8. Use
This makes code signing withmatch
orsigh
gym
easier -
9. Keep Lanes Simple
Use lane composition, actions, and plugins
1. Install with bundler
Create Gemfile
$ bundle init
Edit Gemfile
source "https://rubygems.org"
gem "fastlane"
Install gems
$ bundle install
- Keep fastlane and its dependencies consistant
-
Good for when fastlane shells out commands
-
Ex: fastlane will execute
bundle exec pod install
which will run the same CocoaPods gem version installed in theGemfile
-
Ex: fastlane will execute
-
Needed if third-party plugins are used
-
fastlane will load a
Pluginfile
from theGemfile
when installing plugins - This will be covered in a later slide
-
fastlane will load a
1. Install with bundler
cont'd
Example Gemfile
source "https://rubygems.org"
gem "fastlane"
gem "cocoapods"
# Added by fastlane when installing plugins
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
2. Platforms
- Group/namespace lanes by platform
- Used by running
fastlane <platform> <lane>
lane :bump_version do
# This doesn't belong to a platform
end
platform :ios do
lane :build do
# Do ios build stuff
end
end
platform :mac do
lane :build do
# Do mac build stuff
end
end
platform :android do
lane :build do
# Do android build stuff
end
end
3. Lane Options and UI
- Pass options to a lane:
fastlane <lane> opt1:val1 opt2:val2
-
Get user input with
UI
class
lane :bump do |options|
# Prompt version number
version = nil
loop do
version = options[:version] || UI.input("Version?")
break if version && !version.empty?
end
# Prompt build number
build_number = options[:build_number] || UI.input("Build number (defaults to current timestamp)?")
build_number = Time.now.to_i if build_number.nil? || build_number.empty?
# Update plist with new version and build number
update_info_plist(
xcodeproj: 'Test.xcodeproj',
plist_path: 'Test/Info.plist',
block: proc do |plist|
plist["CFBundleShortVersionString"] = version
plist["CFBundleVersion"] = build_number
end
)
end
4. Lane Description
desc "Bumps the version and build number on the project"
desc "The lane to run by developers"
desc "#### Example:"
desc "```\nfastlane ios bump version:2.0.1 build_number:23\n```"
desc "#### Options"
desc " * **`version`**: The version to set in the Info.plist (`CFBundleShortVersionString`)"
desc " * **`build_number`**: The build number to set in the Info.plist (`CFBundleVersion`)"
desc ""
lane :bump do
# See previous slide for logic
end
4. Lane Description cont'd
5. Environment Variables
Put non-secret values in .env
# fastlane/.env
GYM_PROJECT=Example.xcodeproj
GYM_SCHEME=development
Put --env
specific values in .env.<environment>
-
These get loaded when
fastlane <lane> --env <environment>
gets run
# fastlane/.env.staging
GYM_SCHEME=staging
# fastlane/.env.production
GYM_SCHEME=production
Load secret values from .env.secret
- Add
.env.secret
to.gitignore
so not to commit secret values - Call
Dotenv.load ".env.secret"
at top ofFastfile
# fastlane/.env.secret
FASTLANE_PASSWORD=shhhhhh
fastlane_require "dotenv"
Dotenv.load ".env.secret"
5. Environment Variables cont'd
fastlane_require "dotenv"
Dotenv.load(".env.secret")
lane :test do
UI.message("GYM_PROJECT: #{ENV['GYM_PROJECT']}") # Prints "Example.xcodeproj"
UI.message("GYM_SCHEME: #{ENV['GYM_SCHEME']}") # Prints "development", "staging", or "production"
UI.message("FASTLANE_PASSWORD: #{ENV['FASTLANE_PASSWORD']}") # Prints "shhhhhh"
end
6. fastlane Documentation
7. Separate Apple ID
Instead of<EMAIL_ADDRESS>... Use<EMAIL_ADDRESS>- Prevents from having to use a personal email/password
- Especially if two-step or two-factor auth is enabled
- Can revoke access at anytime (great for CI)
8. Use match
or sigh
before gym
- Xcode 9 requires that an
-exportOptionsPlist
be passed to thexcodebuild
command that gym generates - This
exportOptionsPlist
is required to have a key forprovisioningProfiles
- This can be manually passed into gym through
export_options
like the following:
lane :build do
gym(
export_options: {
"provisioningProfiles": {
"com.joshholtz.FastlaneDemo": "match AppStore com.joshholtz.FastlaneDemo",
},
"method": "app-store",
"signingStyle": "manual"
}
)
end
But this can be easier with by calling match
or sigh
🚀
8. Use match
or sigh
before gym
cont'd
lane :build do
sigh(
app_identifier: "com.joshholtz.FastlaneDemo"
)
gym()
end
By calling sigh
(or match
), fastlane will...
- Automatically create
exportOptionsPlist
- Automatically set
provisioningProfiles
key with profiles that were created or downloaded - Automatically set
method
depending on what was passed into sigh or match
9. Keep Lanes Simple - Lane Composition
Call another lane
or private_lane
from a lane
Our previous :bump
lane can be cleaned up like:
lane :bump do |options|
# Update plist with new version and build number
update_info_plist(
xcodeproj: 'Test.xcodeproj',
plist_path: 'Test/Info.plist',
block: proc do |plist|
plist["CFBundleShortVersionString"] = get_version(options)
plist["CFBundleVersion"] = get_build_number(options)
end
)
end
private_lane :get_version do |options|
version = nil
loop do
version = options[:version] || UI.input("Version?")
break if version && !version.empty?
end
version
end
private_lane :get_build_number do |options|
build_number = options[:build_number] || UI.input("Build number (defaults to current timestamp)?")
build_number = Time.now.to_i if build_number.nil? || build_number.empty?
build_number
end
9. Keep Lanes Simple - Custom Action
Sometimes lanes need to have some custom Ruby implementation
In this contrived example, we are going to set our app name to a randomly selected Star Wars character
lane :star_wars do
fastlane_require "rest-client"
resp = RestClient.get "https://swapi.co/api/people/"
json = JSON.parse(resp.body)
people = json["results"]
random_person = people.sample
update_info_plist(
xcodeproj: 'Test.xcodeproj',
plist_path: 'Test/Info.plist',
block: proc do |plist|
plist["CFBundleDisplayName"] = random_person['name']
end
)
sigh()
gym()
end
9. Keep Lanes Simple - Custom Action cont'd
-
Create new action with
fastlane new_action
- Give your action a name
-
Open up your newly created action in
./fastlane/actions
directory -
Fill out the templated methods and put your logic in the
run
method
module Fastlane
module Actions
module SharedValues
STAR_WARS_API_LAST_RESPONSE = :STAR_WARS_API_LAST_RESPONSE
STAR_WARS_API_COUNT = :STAR_WARS_API_COUNT
STAR_WARS_API_NEXT = :STAR_WARS_API_NEXT
STAR_WARS_API_PREVIOUS = :STAR_WARS_API_PREVIOUS
end
class StarWarsApiAction < Action
def self.run(params)
fastlane_require "rest-client"
resp = RestClient.get "https://swapi.co/api#{params[:route]}"
json = JSON.parse(resp.body)
Actions.lane_context[SharedValues::STAR_WARS_API_LAST_RESPONSE] = json
Actions.lane_context[SharedValues::STAR_WARS_API_COUNT] = json["count"]
Actions.lane_context[SharedValues::STAR_WARS_API_NEXT] = json["next"]
Actions.lane_context[SharedValues::STAR_WARS_API_PREVIOUS] = json["previous"]
json["results"]
end
#####################################################
# @!group Documentation
#####################################################
def self.description
"Call Star Wars API"
end
def self.details
"Call Star Wars API because Star Wars is awesome"
end
def self.available_options
[
FastlaneCore::ConfigItem.new(key: :route,
env_name: "FL_STAR_WARS_API_ROUTE",
description: "The route to call on Star Wars API",
required: true
end)
]
end
def self.output
[
['STAR_WARS_API_LAST_RESPONSE', 'Last resopnse because why not']
]
end
def self.return_value
"Hash with person info"
end
def self.authors
["joshdholtz"]
end
def self.is_supported?(platform)
[:ios, :android, :mac].include?(platform)
end
end
end
end
9. Keep Lanes Simple - Custom Action cont'd
- Now replace custom logic in the lane with new action name
- The new action code is easier to maintain and Test
- The new acttion has documentation that other developers can reference
- The action can easily be reused
- The faslane output now shows when new action is being called
lane :star_wars do
random_person = star_wars_api(route: "/people/").sample
update_info_plist(
xcodeproj: 'Test.xcodeproj',
plist_path: 'Test/Info.plist',
block: proc do |plist|
plist["CFBundleDisplayName"] = random_person['name']
end
)
sigh()
gym()
end
9. Keep Lanes Simple - Custom Plugin cont'd
- A plugin is 100% the same thing as an action but contained in its own repository
- It is created outside of a fastlane project with templated tests and a README
- More information can be found on the docs page on how to create - https://docs.fastlane.tools/plugins/create-plugin/


Our Services
WordPress Website Development
WordPress has made the lives easier to get the fully functional website developed in quick time. Novice users can easily manage the content of the website. You can make changes to site without making changes to the website coding. But still, you need professionals to get the website up and running. Customized, Highly Attractive and Unique WordPress Solutions is the core aspect of our web development services. WordPress is an easy solution to your website needs because it is:
- Easy to Manage
- Search Engine Friendly
- Cost Effective
Laravel Website Development
Laravel is one of the most efficient frameworks which is used for developing complex functionalities with a great accuracy. Laravel is a framework of Hypertext Preprocessor which is based on the MVC system. Our Highly Skilled Laravel developers are experienced to make healthy and flawless applications with a clean code. Besides, Laravel is one of the most secure platform for web development.
- Highly Protected Framework
- Excessive-quit and upgraded features
- Best Loading Speed
PHP & MySql
PHP and MySQL are significant and widely utilized open-source technologies that are ideal for quick development of database-driven web applications or customized websites. Our professional web developers constantly provide the most extensive PHP web applications and solutions for all commercial areas with outstanding domain expertise.
- Easy Authentication system
- Clean and simple API
- Faster and Less Costly


| TREVOR PETERSON. | About Work Experiences Contact |
Business Driven.
|
I am currently a Master’s of Industrial & Labor Relations student at Cornell University. My business mindset coupled with the strategic learnings of the program have allowed me to tackle a variety of organizational issues. Visual management, standard work, and the creation of novel programs are just a few experiences detailed below that display my passion and capability to help drive positive business outcomes. Known to be a quick learner by peers and supervisors, I approach problems with an analytical approach that helps me thrive in autonomous environments and delve deep into both quantitative and qualitative problems.
What sets me apart? I indulge myself in business activities outside of the workplace. For the past 6 years I have bought and sold over 500 items including shoes, speakers, and motorbikes. This hobby has allowed me to understand the importance of customer interaction, marketing, and ROI. My drive has helped me build my own brand and reputation which has given me key, transferable insights into how to be successful in the business world.


There’s no question that watching films can help us escape our everyday lives. However, all kinds of films impact our society and popular culture in many different ways all over the world. Studies have shown that many people believe that cops may sometimes break the law in order to enforce it and they are quite okay with this. There have been several cases where by suspects have been bitten up until they confessed to crimes they did not commit leaving out the true criminals,but doesn’t this turn them into the very criminals we entrusted them to put behind bars. Films such as ‘Cops’ which was a popular American Tv show was recently canceled due to the black lives matter movement as it glorified police brutality especially towards people of color.
Films however do also have a positive effect on society mainly sci-fi movies and series.Most of them act as a warning against global problems that are seeded deep within our siciety and others which we ignore such as global warming.Films such as ‘Alterd Carbon” depict how immoral and inhuman a society can possibly be without proper authority .
Alterd Carbon :More than 300 years in the future, society has been transformed by new technology, leading to human bodies being interchangeable and death no longer being permanent. Takeshi Kovacs is the only surviving soldier of a group of elite interstellar warriors who were defeated in an uprising against the new world order. His mind was imprisoned for centuries until impossibly wealthy businessman Laurens Bancroft offers him the chance to live again. Kovacs will have to do something for Bancroft, though, if he wants to be resurrected. Bancroft's request of Kovacs is to solve a murder -- Bancroft's. "Altered Carbon" is based on Richard K. Morgan's cyberpunk noir novel of the same name
The Expance:Hundreds of years in the future, things are different than what we are used to after humans have colonized the solar system and Mars has become an independent military power. Rising tensions between Earth and Mars have put them on the brink of war. Against this backdrop, a hardened detective and a rogue ship's captain come together to investigate the case of a missing young woman. The investigation leads them on a race across the solar system that could expose the greatest conspiracy in human history.
Films also play a great role in empowering women as they encourage women to aim for great positions of power in their offices and also in leadership.The Great:A genre-bending, anti-historical ride through 18th-century Russia following the wildly comedic rise of Catherine the Nothing to Catherine the Great.
The 100:A nuclear conflict has decimated civilisation. A century later, a spaceship accommodating humanity's lone survivors dispatch 100 juvenile delinquents back to the Earth to determine its habitability.


--- layout: page title: Core Area 1 - Course, learners and learning outcomes image: /assets/images/portfolio.jpg ---
As a working case for this portfolio, I have selected the course Nordic Climate Change Studies (CCGA08). I taught this course for the first time in the autumn semester of 2019 with an allowance of 260 hours. Below I describe the details of the course that are relevant for the portfolio, characteristics of the learners and the intended learning outcomes found in the course syllabus in the following subsections.
CCGA08 was originally designed in 2012 to offer to the incoming students of Lüneburg University, Germany, as a part of a teacher and student exchange program established with Karlstad University through the Linnaeus Palme scholarship. Since then, the course has been offered every year (either in Spring or Autumn semester), predominantly to the exchange students from this program, but also to the international exchange students in other programs and interested students in general in Karlstad University. The course aims to provide basic and advanced knowledge about climate change and its global impacts, with a focus on Sweden and the Nordic countries. Adaptation and mitigation responses along with the global and Nordic policies to tackle climate change are also covered in this course.
The course comprises two modules: (i) a problem module, where the nature and evidence of climate change and its social-ecological impacts are taught, and (ii) a solution module, where the policy, adaptation and mitigation tools for solving climate change problem are delivered to the students. Each module is consist of six lectures, a seminar and an excursion (3-7 days) to places of special interests in Nordic countries. Climate change related extreme weather events like floods, and glaciers, as well as local mitigation and adaptation efforts are studied during the excursions.
CCGA08 was taught between week 36 of 2019 and week 2 of 2020 at a 50% (Day) pace. The course has upper‐secondary level entry requirements (G1N) and is taught in undergraduate level (although students from postgraduate level, i.e. master's at Karlstad University participated). The admission requirements are general and a upper secondary level English 6, or equivalent. Further details about the course is available at the Karlstad University website (www.kau.se) and the Canvas page (kau.instructure.com/courses/5681).
Although the course was originally designed for the exchange students from Lüneburg University, Germany, I received students from all over the world (e.g. South Korea, U.S.A., Ethiopia) including international students from other study programs at Karlstad University. The age group of the students is around 25 years and their level of current education ranged from bachelor's to master's. The female and male students covered 60% and 40% of the participants, respectively. A survey was conducted to extract students' previous knowledge and experience of climate change and expectation from the course, before the start of the course. The background of the students ranged from computer science, business administration to political and sustainability science, which diverse cultural and hence educational context and knowledge about climate change.
A part of the CCGA08 Autumn 2019 participants with me.Below I describe my colleague (Max Hansson) and my interpretation of the four intended learning outcomes (ILO) of CCGA08:


An "historical fiction" showing today's COVID-19 tracking dashboard re-imagined with data from the 1918 Spanish Flu pandemic.
Here is the actual COVID-19 dashboard from the Ministry of Health
An "historical fiction" showing today's COVID-19 tracking dashboard re-imagined with data from an imagined outbreak 102 years in the future (COVID-2122).
Death by Numbers: New Zealand Mortality Rates in the 1918 Influenza Pandemic (PDF)
Te Ara: The Encyclopaedia of New Zealand - The influenza era, 1890s to 1920s
Black November: The 1918 Influenza Pandemic in New Zealand by Geoffrey W. Rice
https://www.parliament.nz/en/get-involved/features/centenary-of-the-1918-flu-pandemic/
https://mch.govt.nz/1918-influenza-pandemic-memorial-plaque-unveiled-today
https://mch.govt.nz/significant-sites/1918-influenza-pandemic-memorial-plaque
https://discover.stqry.com/v/influenza-memorial/s/d6add63b1c06c67e48dfa74f4050a7e6
https://www.beehive.govt.nz/release/major-steps-taken-protect-new-zealanders-covid-19


Is it raining?
There is currently
at location
,
.
Probability
, Intensity
.
Today there is a
chance of
.
Powered by Dark Sky
Fork me on GitHub


This document is for dokku's development version, which can be significantly different from previous releases. For older releases, use the version selector floating in the bottom right corner of this page.
This document is for dokku's development version, which can be significantly different from previous releases. For older releases, use the version selector floating in the bottom right corner of this page.


| stargazer-package | stargazer |
| list of statistic codes | stargazer: list of statistic codes |
| list of summary statistic codes | stargazer: list of summary statistic codes |
| list of supported styles | stargazer: list of supported styles |
| stargazer | stargazer |
| stargazer models | stargazer: list of supported objects |
| stargazer news | What's new? |
| stargazer package acknowledgments | Acknowledgments |
| table layout characters | stargazer: table layout characters |


| Ganglia Monitoring Daemon v3.1.2 Configuration |
gmond.conf - configuration file for ganglia monitoring daemon (gmond)
The gmond.conf file is used to configure the ganglia monitoring daemon (gmond) which is part of the Ganglia Distributed Monitoring System.
All sections and attributes are case-insensitive. For example, name or NAME or Name or NaMe are all equivalent.
Some sections can be included in the configuration file multiple times and some sections are singular. For example, you can have only one cluster section to define the attributes of the cluster being monitored; however, you can have multiple udp_recv_channel sections to allow gmond to receive message on multiple UDP channels.
There should only be one cluster section defined. This section controls how gmond reports the attributes of the cluster that it is part of.
The cluster section has four attributes: name, owner, latlong and url.
For example,
cluster { name = "Millennium Cluster" owner = "UC Berkeley CS Dept." latlong = "N37.37 W122.23" url = "http://www.millennium.berkeley.edu/" }
The name attributes specifies the name of the cluster of machines. The owner tag specifies the administrators of the cluster. The pair name/owner should be unique to all clusters in the world.
The latlong attribute is the latitude and longitude GPS coordinates of this cluster on earth. Specified to 1 mile accuracy with two decimal places per axis in decimal.
The url for more information on the cluster. Intended to give purpose, owner, administration, and account details for this cluster.
There directives directly control the XML output of gmond. For example, the cluster configuration example above would translate into the following XML.
<CLUSTER NAME="Millennium Cluster" OWNER="UC Berkeley CS Dept." LATLONG="N37.37 W122.23" URL="http://www.millennium.berkeley.edu/"> ... </CLUSTER>
The host section provides information about the host running this instance of gmond. Currently only the location string attribute is supported. Example:
host { location = "1,2,3" }
The numbers represent Rack, Rank and Plane respectively.
The globals section controls general characteristics of gmond such as whether is should daemonize, what user it should run as, whether is should send/receive date and such. The globals section has the following attributes: daemonize, setuid, user, debug_level, mute, deaf, allow_extra_data, host_dmax, cleanup_threshold, gexec, send_metadata_interval and module_dir.
For example,
globals { daemonize = true setuid = true user = nobody host_dmax = 3600 }
The daemonize attribute is a boolean. When true, gmond will daemonize. When false, gmond will run in the foreground.
The setuid attribute is a boolean. When true, gmond will set its effective UID to the uid of the user specified by the user attribute. When false, gmond will not change its effective user.
The debug_level is an integer value. When set to zero (0), gmond will run normally. A debug_level greater than zero will result in gmond running in the foreground and outputting debugging information. The higher the debug_level the more verbose the output.
The mute attribute is a boolean. When true, gmond will not send data regardless of any other configuration directives.
The deaf attribute is a boolean. When true, gmond will not receive data regardless of any other configuration directives.
The allow_extra_data attribute is a boolean. When false, gmond will not send out the EXTRA_ELEMENT and EXTRA_DATA parts of the XML. This might be useful if you are using your own frontend to the metric data and will like to save some bandwith.
The host_dmax value is an integer with units in seconds. When set to zero (0), gmond will never delete a host from its list even when a remote host has stopped reporting. If host_dmax is set to a positive number then gmond will flush a host after it has not heard from it for host_dmax seconds. By the way, dmax means ``delete max''.
The cleanup_threshold is the minimum amount of time before gmond will cleanup any hosts or metrics where tn > dmax a.k.a. expired data.
The gexec boolean allows you to specify whether gmond will announce the hosts availability to run gexec jobs. Note: this requires that gexecd is running on the host and the proper keys have been installed.
The send_metadata_interval establishes an interval in which gmond will send or resend the metadata packets that describe each enabled metric. This directive by default is set to 0 which means that gmond will only send the metadata packets at startup and upon request from other gmond nodes running remotely. If a new machine running gmond is added to a cluster, it needs to announce itself and inform all other nodes of the metrics that it currently supports. In multicast mode, this isn't a problem because any node can request the metadata of all other nodes in the cluster. However in unicast mode, a resend interval must be established. The interval value is the minimum number of seconds between resends.
The module_dir is an optional parameter indicating the directory where the DSO modules are to be located. If absent, the value to use is set at configure time with the --with-moduledir option which will default if omitted to the a subdirectory named ``ganglia'' in the directory where libganglia will be installed.
For example, in a 32-bit Intel compatible Linux host that is usually:
/usr/lib/ganglia
You can define as many udp_send_channel sections as you like within the limitations of memory and file descriptors. If gmond is configured as mute this section will be ignored.
The udp_send_channel has a total of five attributes: mcast_join, mcast_if, host, port and ttl.
For example, the 2.5.x version gmond would send on the following single channel by default...
udp_send_channel { mcast_join = <IP_ADDRESS> port = 8649 }
The mcast_join and mcast_if attributes are optional. When specified gmond will create the UDP socket and join the mcast_join multicast group and send data out the interface specified by mcast_if.
If only a host and port are specified then gmond will send unicast UDP messages to the hosts specified. You could specify multiple unicast hosts for redundancy as gmond will send UDP messages to all UDP channels.
For example...
udp_send_channel { host = host.foo.com port = 2389 } udp_send_channel { host = <IP_ADDRESS> port = 2344 }
would configure gmond to send messages to two hosts. The host specification can be an IPv4/IPv6 address or a resolvable hostname.
You can specify as many udp_recv_channel sections as you like within the limits of memory and file descriptors. If gmond is configured deaf this attribute will be ignored.
The udp_recv_channel section has following attributes: mcast_join, bind, port, mcast_if, family. The udp_recv_channel can also have an acl definition (see ACCESS CONTROL LISTS below).
For example, the 2.5.x gmond ran with a single udp receive channel...
udp_recv_channel { mcast_join = <IP_ADDRESS> bind = <IP_ADDRESS> port = 8649 }
The mcast_join and mcast_if should only be used if you want to have this UDP channel receive multicast packets the multicast group mcast_join on interface mcast_if. If you do not specify multicast attributes then gmond will simply create a UDP server on the specified port.
You can use the bind attribute to bind to a particular local address.
The family address is set to inet4 by default. If you want to bind the port to an inet6 port, you need to specify that in the family attribute. Ganglia will not allow IPV6=>IPV4 mapping (for portability and security reasons). If you want to listen on both inet4 and inet6 for a particular port, explicitly state it with the following:
udp_recv_channel { port = 8666 family = inet4 } udp_recv_channel { port = 8666 family = inet6 }
If you specify a bind address, the family of that address takes precedence. f your IPv6 stack doesn't support IPV6_V6ONLY, a warning will be issued but gmond will continue working (this should rarely happen).
Multicast Note: for multicast, specifying a bind address with the same value used for mcast_join will prevent unicast UDP messages to the same port from being processed.
You can specify as many tcp_accept_channel sections as you like within the limitations of memory and file descriptors. If gmond is configured to be mute, then these sections are ignored.
The tcp_accept_channel has the following attributes: bind, port, interface, family and timeout. A tcp_accept_channel may also have an acl section specified (see ACCESS CONTROL LISTS below).
For example, 2.5.x gmond would accept connections on a single TCP channel.
tcp_accept_channel { port = 8649 }
The bind address is optional and allows you to specify which local address gmond will bind to for this channel.
The port is an integer than specifies which port to answer requests for data.
The family address is set to inet4 by default. If you want to bind the port to an inet6 port, you need to specify that in the family attribute. Ganglia will not allow IPV6=>IPV4 mapping (for portability and security reasons). If you want to listen on both inet4 and inet6 for a particular port, explicitly state it with the following:
tcp_accept_channel { port = 8666 family = inet4 } tcp_accept_channel { port = 8666 family = inet6 }
If you specify a bind address, the family of that address takes precedence. If your IPv6 stack doesn't support IPV6_V6ONLY, a warning will be issued but gmond will continue working (this should rarely happen).
The timeout attribute allows you to specify how many microseconds to block before closing a connection to a client. The default is set to 1 second (1000000 usecs). If you have a very slow connection you may need to increase this value.
The interface is not implemented at this time (use bind).
You can specify as many collection_group section as you like within the limitations of memory. A collection_group has the following attributes: collect_once, collect_every and time_threshold. A collection_group must also contain one or more metric sections.
The metric section has the following attributes: name, value_threshold and title. For a list of available metric names, run the following command:
% gmond -m
Here is an example of a collection group for a static metric...
collection_group { collect_once = yes time_threshold = 1800 metric { name = "cpu_num" title = "Number of CPUs" } }
This collection_group entry would cause gmond to collect the cpu_num metric once at startup (since the number of CPUs will not change between reboots). The metric cpu_num would be send every 1/2 hour (1800 seconds). The default value for the time_threshold is 3600 seconds if no time_threshold is specified.
The time_threshold is the maximum amount of time that can pass before gmond sends all metrics specified in the collection_group to all configured udp_send_channels. A metric may be sent before this time_threshold is met if during collection the value surpasses the value_threshold (explained below).
Here is an example of a collection group for a volatile metric...
collection_group { collect_every = 60 time_threshold = 300 metric { name = "cpu_user" value_threshold = 5.0 title = "CPU User" } metric { name = "cpu_idle" value_threshold = 10.0 title = "CPU Idle" } }
This collection group would collect the cpu_user and cpu_idle metrics every 60 seconds (specified in collect_every). If cpu_user varies by 5.0% or cpu_idle varies by 10.0%, then the entire collection_group is sent. If no value_threshold is triggered within time_threshold seconds (in this case 300), the entire collection_group is sent.
Each time the metric value is collected the new value is compared with the old value collected. If the difference between the last value and the current value is greater than the value_threshold, the entire collection group is send to the udp_send_channels defined.
It's important to note that all metrics in a collection group are sent even when only a single value_threshold is surpassed.
In addition a user friendly title can be substituted for the metric name by including a title within the metric section.
A modules section contains the parameters that are necessary to load a metric module. A metric module is a dynamically loadable module that extends the available metrics that gmond is able to collect. Each modules section contains at least one module section. Within a module section are the directives name, language, enabled, path and params. The module name is the name of the module as determined by the module structure if the module was developed in C/C++. Alternatively, the name can be the name of the source file if the module has been implemented in a interpreted language such as python. A language designation must be specified as a string value for each module. The language directive must correspond to the source code language in which the module was implemented (ex. language = ``python''). If a language directive does not exist for the module, the assumed language will be ``C/C++''. The enabled directive allows a metric module to be easily enabled or disabled through the configuration file. If the enabled directive is not included in the module configuration, the enabled state will default to ``yes''. One thing to note is that if a module has been disabled yet the metric which that module implements is still listed as part of a collection group, gmond will produce a warning message. However gmond will continue to function normally by simply ignoring the metric. The path is the path from which gmond is expected to load the module (C/C++ compiled dynamically loadable module only). The params directive can be used to pass a single string parameter directly to the module initialization function (C/C++ module only). Multiple parameters can be passed to the module's initialization function by including one or more param sections. Each param section must be named and contain a value directive. Once a module has been loaded, the additional metrics can be discovered by invoking gmond -m.
modules { module { name = "example_module" enabled = yes path = "modexample.so" params = "An extra raw parameter" param RandomMax { value = 75 } param ConstantValue { value = 25 } } }
This directive allows the user to include additional configuration files rather than having to add all gmond configuration directives to the gmond.conf file. The following example includes any file with the extension of .conf contained in the directory conf.d as if the contents of the included configuration files were part of the original gmond.conf file. This allows the user to modularize their configuration file. One usage example might be to load individual metric modules by including module specific .conf files.
include ('/etc/ganglia/conf.d/*.conf')
The udp_recv_channel and tcp_accept_channel directives can contain an Access Control List (ACL). This ACL allows you to specify exactly which hosts gmond process data from.
An example of an acl entry looks like
acl { default = "deny" access { ip = <IP_ADDRESS> mask = 32 action = "allow" } }
This ACL will by default reject all traffic that is not specifically from host <IP_ADDRESS> (the mask size for an IPv4 address is 32, the mask size for an IPv6 address is 128 to represent a single host).
Here is another example
acl { default = "allow" access { ip = <IP_ADDRESS> mask = 24 action = "deny" } access { ip = ::ff:<IP_ADDRESS> mask = 120 action = "deny" } }
This ACL will by default allow all traffic unless it comes from the two subnets specified with action = ``deny''.
The default behavior for a 2.5.x gmond would be specified as...
udp_recv_channel { mcast_join = <IP_ADDRESS> bind = <IP_ADDRESS> port = 8649 } udp_send_channel { mcast_join = <IP_ADDRESS> port = 8649 } tcp_accept_channel { port = 8649 }
To see the complete default configuration for gmond simply run:
% gmond -t
gmond will print out its default behavior in a configuration file and then exit. Capturing this output to a file can serve as a useful starting point for creating your own custom configuration.
% gmond -t > custom.conf
edit custom.conf to taste and then
% gmond -c ./custom.conf
The ganglia web site is at http://ganglia.info/.
Copyright (c) 2005 The University of California, Berkeley
| Ganglia Monitoring Daemon v3.1.2 Configuration |


User may export to Excel whatever data is currently displayed in the table view.
User can double-click on an organization, bring up its members in the table view,
then filter the table in any way the user wishes (using the filter boxes at the top of each column),
then press the Excel button and whatever filtered data is displayed in the table then gets exported
into Excel. An Excel window will be popped up automatically. If by chance the user does not have
Excel, User can simply download/install OpenOffice (MS Office equivalent) and that will automatically
be used instead of Excel.
Column selection
The column selection menu can be used to determine which columns get exported into Excel.


Warehouse Keeper Sorint:
Ah, the Demon's Boots. Bring me
1 Manak's Gold Giant
and I'll give you a pair.
Trade
Back to the list of prizes.


Worked on a couple of projects as highlighted Here
Selected among the thirty-five(35) ladies to participate in Dufuna-fem training
exercise out of the two hundred(200) ladies that applied for the program.
Led my team to participate in a hackathon, with my team taking the second place out of six
participating teams.
St. Paul’s Cathedral Anglican church Pankshin, Plateau state.
Diocesan media coordinator
2015-2018
Tasks
Led my team in the effective delivery of media services through the use of easy
worship, Microsoft word and PowerPoint packages.
Projected programs during service, media packages such as pictures, videos and
recording of audio messages.
Information Technology Essentials
Cisco Trainee
September 2011-December 2011
Tasks
Troubleshooting computer software and hardware problems.
Computer Networking using Routers, wires and the likes.
Troubleshooting other Hardware such as Printers.
Collecting and documenting clients Reports on software and
hardware issues.