//Artefact:SoftwareComponent/com/sphenon/engines/Generator

Usage/Operation - Manual

[source]
How to invoke the generator
The most easiest way to invoke the generator is the command line interface, since no Java programming is needed. When learning how to write templates, this is a good start.
Operation Class
The generator package provides a class named . This class implements the
Operation
interface, which declares an
execute
method.
The class can be used in two ways. First, it provides a
main
method, which can be used from the command line. Simply invoke it without arguments and you get an explanation of it's usage.
Secondly, you can create instances of the class, specify the respective parameters and call the
execute
method. This is what the
main
method also does internally.
And finally, there are some static
execute
methods with several arguments. They are provided simply for convenience. Internally, they create an instance, set the parameters and invoke the non-static
execute
method.
Command Line Invocation
The generator package contains an example bash script that performs the aboveexplained invokation. Just invoke it without arguments and get more information. Basically, it expects the name of a template you want to process.
Emacs Integration
To invoke the generator from emacs dired buffers, you need to include some lisp code provided in the file
generator.el
. Either you copy&paste that code into your emacs.el file, or you load that file with (load "my_generator").
Then, in a dired buffer you just press
hyper-g
(or whatever key you configure in your loadfile) on a template and emacs invokes the command line bash script.
DynamicString Integration
A very convenient and interesting way to embed generator capabilities into your application is the
DynamicString
interface.
In the default configuration, you just create a
DynamicString
instance, with an argument of
"g:..."
, where you replace the dots with a generator template. Then, you can call the
get
method to get the evaluated contents of the dynamic string. Internally, a template is prepared and the generator is invoked, but you aren't bothered with any details of this!
Programming Interface
In many cases the
Operation_Generate
class (see above) is already sufficient to invoke the generator from within your programs.
But there is another API beneath that class, providing more fine grained and exhaustive control over the various generator features. Please refer to the generator API documentation for more details.

Usage - Tutorial

[source]
Tutorial
A Simple Template
The following example shows a simple OOGenerator Template.
helloworld.template
G-2.0-plain_java-1.0 Hello world!
Test Execution
To execute the test, the following command can be used. It is assumed, that the jar- and template-file are located in the current directory.
Testaufruf
java -classpath oogenerator.jar com.sphenon.engines.generator.operations.Operation_Generate helloworld.template helloworld.out
Example0000_Unicode
Example0000_Unicode
G-2.0-plain_java-1.0 Maybe the most striking feature of the OOGenerator is it's nice and compact unicode syntax. While it is eye-catching, it's just syntactic sugar, and besides it is optional. There's an alternative syntax available, which is pretty JSP-like. If you don't like both: no problem - just plugin your own syntax frontend. Since unicode syntax looks best - at least we do think so - it is used in the examples here. It is important to use an appropriate unicode font to view them correctly. Most moderately recent browsers should have no problem with this, while some text editors might need tuning. If you prefer to use the ASCII (JSP like) syntax, note that there is a converter available, which transforms one syntax into the other in both directions. ------------------------------------------------------------------------- Here is a list of correspondences between Unicode and ASCII syntax: « java code » <% java code %> ⊰ comment ⊱ <%-- comment --%> ⊰✉ message ⊱ <%--#{message} message --%> ⊰✏ doclet ⊱ <%--#{doclet} doclet --%> ⊰⚒ work ⊱ <%--#{work} work --%> ◂ print code ▸ <%= print code %> ◂ print code ⌘encoding▸ <%= print code %%encoding%> ◂⊙▸ <%=#{current}()%> ◂Ⓘ▸ <%=#{index}()%> ▼ file level code (import) ▼ <%@ file level code (import) %> ▲ class level code (declaration) ▲ <%! class level code (declaration) %> ⊏ template code ⊐ <%? template code ?%> ⊏ signature(...) ⊐ <%? signature(...) ?%> ⊏ ➜ somepart(...) ⊐ <%? #{insert} somepart(...) ?%> ⊏ ⌘ ⊐...⊏ /⌘ ⊐ <%? %% ?%>...<%? /%% ?%> ◂‖"Ⓧ/./path/expression"▸ <%= ::"XPath/./path/expression"%> ◂‖"Ⓟ/..."▸ <%= ::"Property/..."%> ◂‖"✦/..."▸ <%= ::"XModel/..."%> ◂ recoded ⌘xml/html▸ <%= recoded %%xml/html%> ⊏ Ⓣ somepart(...) ⊐...⊏ /Ⓣ ⊐ <%? #{template} somepart(...) ?%>...<%? /#{template} ?%> ≤ Java Template ≥ <- Java Template -> ≦ Model Template ≧ <= Model Template => ⑊◂ escaped ⑊▸ ◂ escaped ▸ ⋖ tag(a,b,c) ⋗ <@ tag(a,b,c) @> ●(...){ ... }/● #{select}(...){ ... }/#{select} ∃(...){ ... }/∃ #{exists}(...){ ... }/#{exists} ⁇(...){ ... }/⁇ #{isvalid}(...){ ... }/#{isvalid} ¬⁇(...){ ... }/¬⁇ #{isinvalid}(...){ ... }/#{isinvalid} ∅(...){ ... }/∅ #{empty}(...){ ... }/#{empty} ¬∅(...){ ... }/¬∅ #{notempty}(...){ ... }/#{notempty} ⇾(...){ ... }/⇾ #{isa}(...){ ... }/#{isa} ∀(...){ ... }/∀ #{for}(...){ ... }/#{for} ∀(...∪...){ ... }/∀ #{for}(...#{union}...){ ... }/#{for} ∀(...){ ➀{...}∨{...}/➀ ... }/∀ #{for}(...){ #{first}(){...}#{else}(){...}/#{first} ... }/#{for} ∀(...){ ¬➀{...}∨{...}/¬➀ ... }/∀ #{for}(...){ #{notfirst}(){...}#{else}(){...}/#{notfirst} ... }/#{for} ➀:(...) #{declarepass}(...) ¶(...) /¶ #{indent}(...) /#{indent} Ⓡpattern=replacement ~~~pattern=replacement ⏎ \n … \ ⋮ <%|
Example0010_HelloWorld
Example0010_HelloWorld
G-2.0-plain_java-1.0 ⊰ This templates creates a text with the famous words "Hello, world!". ⊱ Hello, world!
Example0020_Comment
Example0020_Comment
G-2.0-plain_java-1.0 ⊰ This templates does not produce any output, but an empty file. It demonstrates the use of template comments. These comments do not show up anywhere except in the template source. ⊱
Example0030_Expression
Example0030_Expression
G-2.0-plain_java-1.0 ⊰ This templates demonstrates the use of embedded java expressions. ⊱ ⊰ The first example is just another way to say "Hello, world!". The placeholder ◂...▸ is replaced by the value of the java expression between the filled arrows. ⊱ Hello, ◂"world"▸! ⊰ So, any valid java expression is usable. ⊱ Hello, ◂"w"+"o"+"r"+"l"+"d"▸! 2 * 21 = ◂2*21▸
Example0040_Argument
Example0040_Argument
G-2.0-plain_java-1.0 ⊰ This templates allows to greet arbitrary planets (not just worlds). It demonstrates the use of template arguments. When invoked, this templated receives an argument named "my_arg". E.g., if the actual invocation argument is "Mars", it creates the text "Hello, Mars!" ⊱ ⊏ signature(String my_arg) ⊐ Hello, ◂my_arg▸! ⊰ Note the special characters "⊏" and "⊐" around the signature. These are socalled "template code delimiters". The code inside them is processed by the template parser, in contrast to java code inside "«" and "»". The latter - Java code - is passed directly to the created intermediate Java generator class. It is useful to keep these different processing levels in mind. ⊱
Example0050_DefaultValue
Example0050_DefaultValue
G-2.0-plain_java-1.0 ⊰ This templates allows to greet arbitrary planets, but by default the world. It demonstrates the use of default values for template arguments. If invoked without an argument, it prints "Hello, world!". ⊱ ⊏ signature(String my_arg = "world") ⊐ Hello, ◂my_arg▸!
Example0060_PrettySyntax
Example0060_PrettySyntax
G-2.0-plain_java-1.0 ⊰ This template demonstrates how to keep your templates readable. There are three tiny syntactic helpers to solve three frequently encountered problems. ⊱ ⊰ To illustrate the first problem, note that between the first comment and the second one (this one) there is a line break. This line break appears not only in the template, but in the output, too. You will want your template being reasonable layouted, while at the same time having nicely layouted results. How to achieve this? First, note the three tiny continuation dots '…' behind the following comment end delimiter: ⊱… ⊰ They simple say: please ignore the line break (they are comparable to the use of a backslash in programming languages like C or C++). ⊱… ⊰ Another problem often encountered is the indentation depth mismatch between template code and result code. E.g. ⊱… Hello, world! ⊰ is of course indented in the output by 30 spaces. How to avoid this, without compromising template layout? That's the purpose of the indentation character '⋮', like here ⊱… ⋮Hello, world! ⊰ The '⋮' character says: please ignore every whitespace between it and the beginning of the line. So, if you combine these concepts, you might e.g. write ⊱… ⋮Hello, … ⋮◂"world"▸… ⋮!… ⊰ which creates again "Hello, world!", without any additional spaces or line breaks before, after of within the output. ⊱… ⊰ And finally, sometimes you may need the contrary of the continuation dots: a linebreak in the output, but not in the template. This is the purpose of the 'Return' sign '⏎'. The following code produces 50 emtpy lines in the output: ⊱… ⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎⏎
Example0070_JavaCode
Example0070_JavaCode
G-2.0-plain_java-1.0 ⊰ This templates demonstrates how to embed Java code statements. Like in the previous examples, it prints "Hello, world!" (if invoked without an argument). ⊱… ⊏ signature(String my_arg = "world") ⊐… ⊰ The characters '«' and '»' are used as delimimeters for arbitrary Java code statements. ⊱… « String greeting = "Hello, " + my_arg; »… ◂greeting▸
Example0080_JavaCode2
Example0080_JavaCode2
G-2.0-plain_java-1.0 ⊰ This templates demonstrates the embedding of arbitrary types of Java code. ⊱… « String greeting = "Hello, world!"; »… ◂greeting▸ « if (1 == 2) { » Something is wrong here. « } »… Countdown: « for (int i=10; i>=0; i--) { » ◂i▸« } »
Example0090_TemplateIsAClass
Example0090_TemplateIsAClass
G-2.0-plain_java-1.0 ⊰ Each template is translated into a Java class with the same name and in the same package. Therefore, all features of Java classes are available from within templates, too. ⊱… ⊰ Within two characters '▲...▲' you can define class level code. I.e. you can declare variables and define methods. ⊱… ▲ protected void times(int a, int b) { return a * b; } ▲… 3 * 7 = ◂times(3, 7)▸ ⊰ You can declare class level code multiple times, and at arbitrary locations within your template. ⊱… ▲ static final protected float pi = 3.14159265; ▲… « floar r = 1.0; »… area : ◂ pi * r * r ▸
Example0100_Encoding
Example0100_Encoding
G-2.0-plain_java-1.0 ⊰ Templates produce output. Such output might be just plain ASCII, plain Unicode or might be encoded somehow, say HTML. Furthermore, templates process input, which may or may not be written in the same encoding. And finally, the normal template text might have a third encoding. Let's assume you want to create a Java properties file based on XML input. Then - in the input we have '&lt;', '&gt;' and '&amp;'. - in our template text we just want to write normal Unicode. - in the properties file everything non-ASCII (e.g. german umlauts) must be escaped '\uXXXX' In templates, such a situation is rather the rule then an exception. Instead of writing conversion calls each and everyplace, we just can use the recoding operator '⌘': ⊱… « String xml_input = " immer und überall gilt: 17 &lt; 23 "; »… ◂xml_input⌘XML/JAVAPROP▸ ⊰ You get the output " immer und \u00FCberall gilt: 17 < 23 " The '⌘...' sequence is called a 'recoding'. It consists of a sequence of encoding names. The above example reads 'convert XML to JAVAPROP'. The encoding names are defined in an enumeration class named 'Encoding'. You can use this class also from normal Java code. If we have many such expressions in our template, we can define a default recoding: ⊱… ⊏ ⌘XML/JAVAPROP ⊐… ◂xml_input▸ ⊏ /⌘ ⊐… ⊰ This yields the same result as above. Default encodings can be nested (they apply to included and subtemplates, too, but we do not know yet what these are). ⊱… ⊏ ⌘DOCBOOK/JAVAPROP ⊐… ⋮⊏ ⌘XML/JAVAPROP ⊐… ◂xml_input▸ ⋮⊏ /⌘ ⊐… ⊏ /⌘ ⊐… ⊰ This again yields the same result as above. Encodings need not be complete, they will be combined. ⊱… ⊏ ⌘XML/ ⊐… ◂xml_input⌘/JAVAPROP▸ ⊏ /⌘ ⊐… ⊰ This again yields the same result as above. Note, that a default encoding applies to embedded Java expressions as well as normal template text. What if they are different, as within our example? Then you can apply a different default encoding to these categories. ⊱… ⊏ ⌘[x]XML/JAVAPROP ⊐… ⊏ ⌘[t]UTF8/JAVAPROP ⊐… ◂xml_input▸ This '&lt;' is not translated, since we're here in normal template text, not in an expression. ◂"But this '&lt;' is translated, since we're an expression"▸ ⊏ /⌘ ⊐… ⊏ /⌘ ⊐… ⊰ As you might have guessed, 'x' stands for 'expression' and 't' for 'template text'. ⊱…
Example0110_TemplateTypes
Example0110_TemplateTypes
G-2.0-plain_java-1.0 ⊰ Up to now, all templates begun with this cryptic line: G-2.0-plain_java-1.0 It reads like this: G-2.0 this template requires "Generator, Version 2.0" plain_java-1.0 it is a template of type "plain_java, Version 1.0" The generator version is specified for compatibility reasons. If the generator behaviour changes in future versions, it is used to support old templates, or at least issue a warning about possible problems. The template type specifies the context within which the template is interpreted and executed. "plain_java" means: there's nothing but plain Java available. Some common contexts are: plain_java-1.0 nothing special, just plain Java plain_java_jspstyle-1.0 same, but enabling ASCII (JSP like) syntax java_jpp-1.0 plain Java with a special preprocessor enabled xml-1.0 for processing xml files xml_string-1.0 for processing xml, passed as Strings These contexts will be introduced in more detail in following examples. ⊱…
Example0120_ParserConfiguration
Example0120_ParserConfiguration
G-2.0-plain_java-1.0 ⊰ This example explains how the parser configuration works. It can be safely skipped on a first reading. In the previous example template types were introduced. How do they affect the generation process? When interpreting a template, the first information read is the introductory string: G-2.0-plain_java-1.0 This is translated straight forward to the name of a template parser configuration by replacing the "G" with "TP": TP-2.0-plain_java-1.0 The parsers are very modularized and consist of several exchangable building blocks. A parser configuration is a construction plan for a specific parser, made of such components. To build the parsers, Object Construction Plans (OCPs) are used. For details on OCPs, please refer to <http://www.xocp.org>. Specifically, the parser configurations are placed in the ocp package: com/sphenon/engines/generator/parsers Putting the pieces together, the above parser configuration is found in a file in the ocp path at: com/sphenon/engines/generator/parsers/TP-2.0-plain_java-1.0.ocp In our example, it contains the following plan: <?xml version="1.0" encoding="UTF-8"?> <parser CLASS="TemplateParser" xmlns="http://xmlns.sphenon.com/com/sphenon/engines/generator"> <TOMParser> <BeginHandler OID="mth" CLASS="TCHMain"> <SourceHandler CLASS="TCHCompactUnicodeSyntax2ASCII"> <ASCIISourceHandler CLASS="TCHLanguageDispatcher"> <TextHandler CLASS="TCHText"/> <JavaCodeHandler CLASS="TCHJavaCode"/> <JavaExpressionHandler CLASS="TCHJavaExpression"/> <TemplateCommentHandler CLASS="TCHTemplateComment"/> <TemplateCodeHandler CLASS="TCHTemplateCode"/> <TagHandler CLASS="TCHTag"/> <PPTagHandler CLASS="TCHPPTag"/> </ASCIISourceHandler> </SourceHandler> </BeginHandler> <SourceHandler OIDREF="mth"/> <EndHandler OIDREF="mth"/> </TOMParser> </parser> ⊱…
Example0130_Locators
Example0130_Locators
G-2.0-java_jpp-1.0 ⊰ This example is a bit lengthy, but it's worth reading. One of the major issues with generator templates is their tendency to become clumsy over time, and often plain unreadable. The purpose of templates is to write the desired target output easily and concise - unfortunately, this interferes with controlling code. We've already seen how unicode syntax (Example0000_Unicode) and tiny syntax helpers (Example0060_PrettySyntax) help to keep templates tidy. Another means is of course moving longer code sequences into helper classes. Here's a fourth possibility. A very common type of template code is navigation code. I.e., given some instance, the programmer invokes a sequence of methods to navigate to a target instance. A simple example is: « Person person = ...; Address address = person.getAddress(); Vector<Phone> phones = address.getPhones(); Phone phone = phones.get(2); Prefix prefix = phone.getPrefix(); » If we just want to print the prefix, we can abbreviate like this: The prefix is: ◂person.getAddress().getPhones().get(2).getPrefix()▸ The brackets and "gets" still look a bit clumsy, it looks better with pathes: The prefix is: ◂‖[person]"Ⓟ/Address/Phones/2/Prefix"▸ This is in fact a valid expression that can be used in templates of an appropriate type. Pathes are not directly built into the template parser - this is where "Locators" come into play. The above statement is translated into an invocation of a locator, which handles the path at runtime. The translated code looks similar to this: Locator.resolve("//Property/Address/Phones/2/Prefix", person); (note the translation of the unicode "Ⓟ" into "//Property") At runtime, the locator then translates this into a sequences of "gets", like we've seen before. Admittedly, in this example, the syntactic difference is not too big. But locators are much more powerful than this! In fact, there's a universal concept behind them (you may want to check out <http://www.oorl.org>, too). With pluggable locator extensions, locators can be used to navigate through arbitrary structured data. Instances and their relations are just an example. Other's are: ‖"//File//home/me/myfile.txt" a file in the file system ‖"//Space/company/workplace" a space ‖"//XPath/article/section/title" an element in a xml file ‖"//JavaResource/com/sphenon/basics" a resource in your classpath ‖"//Artefact/org/oomodels" a resource in a project ‖"//Model/org/uml/stereotypes" an element of a UML model ‖"//Address/Germany/Hamburg//Barkenkoppel" a street in a city Moreover, locators can be concatenated ‖"//File//home/me/mytext.dbk/,//XPath/article/title" The last example reads a file in your home directory, parses it with an xml parser and retrieves it's title. In addition to properties, the following unicode abbreviations are predefined in the default preprocessor (CUS2ASCII): Ⓟ Property (Java POJO property access) Ⓧ XPath (navigation in xml, see www.w3c.org and xerces.apache.org) Ⓕ File (navigation in file system) ✦ XModel (UML XModel extension property access) To supported different locator syntaxes, several delimiters are supported: ‖'...' ‖"..." ‖(...) ‖{...} ‖§...§ To use locators, the parser has to know a little bit about the objects that are retrieved. For simple cases like property access, it's enough to declare the template type like we've done in this example: G-2.0-java_jpp-1.0 The associated parser configuration enables the Java preprocessor, and declares the default object type for locators as "Object". For property access this is sufficient. To complete this example here's some more working code. First, we declare two test classes: ⊱… ▲ public class Planet { public String getName() { return "world"; } } public class SolarSystem { public Planet getPlanet() { return new Planet(); } } ▲ ⊰ Then, we create a SolarSystem and use a property to access it's sole planet's name: ⊱… « SolarSystem solar_system = new SolarSystem(); »… Hello, ◂‖[solar_system]"Ⓟ/Planet/Name"▸! ⊰ This, of course, prints "Hello, world!" again. ⊱…
Example0140_LocatorTargets
Example0140_LocatorTargets
G-2.0-java_jpp-1.0 ⊰ As mentioned in the previos example, the parser sometimes needs to know something about the instances a locator returns. This is done by declaring a socalled "locator target": ⊱… ⋮⊏ locatortarget Object = (Object object) ⊐… ⊰ The above statement is a declaration. It delares a locator target named "Object" with an instance type of "Object" and a variable name of "object". To switch between locator targets, the following selector can be used: ⊱… ⋮⊏ locatortarget Object ⊐… ⊰ Note that the declaration of a locator target also implicitly selects it. Therefore, it is not necessary to write: ⊱… ⋮⊏ locatortarget Object = (Object object) ⊐… ⋮⊏ locatortarget Object ⊐…
Example0150_ParserInclusion
Example0150_ParserInclusion
G-2.0-inclusion_test-1.0 ⊰ Now that we know how the parser configuration works, and how a template type selects a configuration, we can define our own template type. Let's assume we want to make a value magically available in all our templates of this new type: ⊱… The magic value is ◂magic_value▸ ! ⊰ First, we define a template type, in our example this is G-2.0-inclusion_test-1.0 As we know now, this type points to a configuration in this OCP file com/sphenon/engines/generator/parsers/TP-2.0-inclusion_test-1.0.ocp This OCP file contains: <?xml version="1.0" encoding="UTF-8"?> <parser CLASS="TemplateParser" xmlns="http://xmlns.sphenon.com/com/sphenon/engines/generator"> <TOMParser> ... <IncludeModules> <Module>com.sphenon.engines.generator.test.Example0150_ParserInclusion_MagicValueDefinition</Module> </IncludeModules> </TOMParser> </parser> This configuration specifies an include module Example0150_ParserInclusion_MagicValueDefinition. Modules have the file extension ".template.module" to distinguish them from normal templates. Syntactically, they are normal templates. The next example shows the content of this module. ⊱…
Example0160_ParserInclusion_MagicValueDefinition (Module)
Example0160_ParserInclusion_MagicValueDefinition (Module)
G-2.0-plain_java-1.0 ⊰ As described in the previous example, Example0150_ParserInclusion, this is a template module. In our example, it defines a magic value, which is now available in all our templates of the newly introduced template type. ⊱… « int magic_value = 42; »…
Example0170_ControlBlocks
Example0170_ControlBlocks
G-2.0-java_jpp-1.0 -*- coding: utf-8; -*- ⊰ As mentioned in the previos example, the parser sometimes needs to know something about the instances a locator returns. This is done by declaring a socalled "locator target": ⊱… « Vector friends = new Vector(); friends.add("Hans"); friends.add("Willy"); friends.add("Susi"); »… ⊰ ⊱… «∀(friend:friends){»… ◂friend▸ «}/∀»… ⊰ ⊱… «∀(friends){»… ◂object▸ «}/∀»… ⊰ ⊱… «∀(friends){»… ◂⊙▸ «}/∀»… ⊰ ⊱… « object = vector; »… «∀(⊙){»… ◂⊙▸ «}/∀»… ⊰ ⊱… «∀(enemies){»… ⋮«∀(-friend:friends){»… ◂⊙▸ prints current enemy! ◂friend⊙▸ prints current friend ⋮«}/∀»… «}/∀»… ⊰ ⊱… «¬∅(⊙){»… Nicht leer! (FEHLER) «}/¬∅»… ⊰ ⊱… «∅(⊙){»… Leer! «}/∅»… ⊰ ⊱… «∀(⊙){»«➀{»My friends: «}∨{», «}/➀»◂⊙▸«}/∀» ⊰ ⊱… My friends: «∀(⊙){»«¬➀{», «}/¬➀»◂⊙▸«}/∀» ⊰ ⊱… ⋮«➀:(xy)»… My friends, 2 times: «∀(⊙){»«¬➀(xy){», «}/¬➀»◂⊙▸«}/∀»«∀(⊙){»«¬➀(xy){», «}/¬➀»◂⊙▸«}/∀» ⊰ ⊱… «∀(⊙){»… Friend number ◂Ⓘ▸ : ◂⊙▸ «}/∀»… ⊰ ⊱… «Ⓘ:(my_index)»… «∀(⊙){»… Friend number ◂Ⓘ(my_index)++▸ : ◂⊙▸ «}/∀»… ⊰ ⊱… String friend = "Hans"; «∃(⊙){»… I've got a friend: ◂⊙▸ «}/∃»… ⊰ ⊱… «∃(friend:⊙){»… I've got a friend: ◂friend▸ «}/∃»… ⊰ ⊱… String friend = null; «¬∃(⊙){»… I'm so lonely! «}/¬∃»… ⊰ ⊱… boolean sun_is_shining = true; «⁇(sun_is_shining){»… Nice day! «}/⁇»… ⊰ ⊱… sun_is_shining = false; «¬⁇(sun_is_shining){»… :-( «}/¬⁇»…