1. Help !
A key area we’ve been working on for a while is our new Groovy documentation. Peter Ledbrook has detailed how you can help us author some sections of the documentation. Read his post here.
Like Peter, you can dedicate a bit of your time on a topic of your choice, to further deepen your understanding of a particular area of Groovy and share your knowledge with your peers.
We really look forward to your contributions!
2. Contributions Walk-Thru
-
Working internet connection
-
Familiarity with computer directory organization, folders, sub-directories and structures of hierarchies
-
Have a GitHub Account and familiarity with concepts about code repositories - also called repo-s
-
Knowledge of computer terminal command line
-
Installed GIT tool
-
Plain text editor like TEXTEDIT, NOTEPAD, gedit, Leafpad; - a tool that does NOT include markup like bold,italics, etc. and saves file in the UTF-8 character set
-
Be familiar with Asciidoctor markup and the syntax reference guide ( more notes are listed below ).
-
Optionally - have the asciidoctor toolchain installed on your local system
-
Be familiar with unit testing of individual programs; it may be necessary to write some new test cases for groovy modules. ( Optional )
-
Enthusiasm and nice writing style
| It’s NOT necessary to have Groovy installed on your local system to be able to write documentation. |
2.1. Join Us !
Please join any of our mailing lists at http://groovy-lang.org/mailing-lists.html.
Whether you are a user, developer, or enthusiast, we have a choice of mailing lists you may find appealing. Ask and get answers for questions about the Groovy eco-system.
You can find live #groovylang feeds for up-to-the-minute news.
2.2. Where is Groovy ?
Open source developers often need somewhere to keep all their assets. These assets are typically stored in a repository somewhere on the internet. GitHub is one such storage facility. At Groovy, we keep our source code here.
2.3. How Do I Contribute ?
There are two paths to contribute :
For small things, you can change the relevant document on-line, within the GitHub system. For spelling or punctuation typos, broken language, etc, you can edit the document live from within Github. We mention this approach for small contributions that don’t require us to run the tests / create or update new tests. Follow this trail.
For larger contributions, it’s more likely you’ll need to copy Groovy into your own work environment, then Take The Long Way Home.
3. Quick Fixes To Groovy
Sometimes, you may spot a tiny flaw in our otherwise perfect product. It’s bugging you, so you want to fix it quickly without all the trouble of porting Groovy to your own system. Can it be done ?
Sure
Let’s say you need to fix the Groovy README.adoc file in https://github.com/apache/incubator-groovy - our core location.
| Only use this way to fix small stuff like spelling bits. Otherwise your fix may avoid our indepth testing process :-( |
Click the core location address to get here :
Your view should look like this, except it will say groovy / groovy-core ( this view was from another example and has the wrong location name ). Confirm you are viewing groovy / groovy-core then click the name of the resource to edit, in this case README.adoc. The following view opens.
This view is the current content of the README file. You can see ( but not edit ) the raw text by clicking the RAW button. But for this example, you want to change some text. The red arrow points to the editor PENCIL. Click that to open an editable version of this page. See below.
Confirm you’re on the correct page ( blue square ). Then on line 80, after the words Continuous Integration add the word Server
Then add more details like this :
In the box marked Commit changes add a short descriptive title and add more detail below. Then click Commit changes button to seal the deal. Easy-peasy
4. Take The Long Way Home
This way needs more work on your part though it it is more rewarding too.
First we look at the home of Groovy . Then we review the structure and important items. After that we pick up the story at Getting Started.
4.1. Notes About GitHub
At Groovy, we keep our source code here.
4.1.1. GitHub Information
Typical Workflow Steps
- join GitHub
- sign in to your GitHub account
- locate the groovy code base
- make a copy ( FORK ) of it into your own online GitHub account
- make a local copy ( CLONE ) from your own online GitHub account
- create a new feature branch
- switch to your new feature branch
- build/amend the documents
- provide screen images if needed
- provide test cases to match your documentation
- build and test everything
- commit your changes
- switch to your master branch
- merge your branch full of changes into the master branch
- send ( PUSH ) your changes back to your own online account
- ask the groovy admins to include ( PULL ) your changes in the groovy code base
Git Clients
Git References
4.2. Groovy Directory Structure
From here on, we’ve assumed you have logged into your own GitHub account.
4.2.1. Visit Groovy Core Repository on GitHub
Open a web browser, then use address https://github.com/apache/incubator-groovy to review the Groovy code base. It looks like this :
There are a number of folders within the Groovy code base. The most important folders are /src and /subprojects as these folders hold the base code and scripts for Groovy.
4.2.2. The /src Folder
The core of Groovy lives within this folder. Here is where we find a variety of artifacts, scripts, tests, resources, images, etc.
4.2.3. The /subprojects Folder
Groovy has many additional features that are not part of the core system. Source code for these added features can be found in the subprojects folder. It looks something like this :
4.2.4. The Documentation Folder
Within each /src and /subproject/src is a /spec documents folder that exists, or will soon be created.
The two most useful folders here are /doc and /test. These two folders hold our documents and test cases.
Documents
All of our documents are written as typical text files encoded as UTF-8 characters. The text is styled in the markup syntax known as asciidoc or asciidoctor ( the more recent version ). These text files have a filename suffix designation of .adoc.
Test Cases
To prove that Groovy modules work as expected, we often construct test cases that exercise code logic. These test cases are actually Groovy scripts that reside in the /test folder.
If you would like to know more about writing effective test cases, please review this link.
5. Getting Started
Let’s assume you’ve logged into your GitHub account.
This is the typical panel you use to work with GitHub. It has a variety of things you can do. You’ll need to search for the Groovy repository, so look at the top of this panel. See that field named Search or type a command ? Let’s use that to .
5.1. Make Groovy Your Own
Ok, let’s look for the groovy-core repository. In the field named Search or type a command enter groovy-core then click Search. You should see a repository named groovy/groovy-core so click that to visit the home of Groovy.
So you can work on your own version of Groovy, you’ll need to make a copy of it. This copy is placed in your own GitHub account under your credentials. This task of making a copy is known as Fork -ing.
Check you’re logged into your own GitHub account before you start to search.
Fork the groovy/groovy-core repository on GitHub to your own GitHub account. Click the Fork button while on the groovy/groovy-core panel. When you look at your own GitHub home page, you’ll see the list of your forked repos and any new repos you make.
You now have your own version of Groovy in your GitHub account on the remote server. Next, you’ll want to bring a copy of it onto your local system. It’s easier to work with documents and test cases that way.
| See this gun.io tutorial covering fork, branch, pull tactics. |
5.2. Terminally Yours
Open a terminal/command prompt
Make a folder to hold your copy of Groovy; for now, create a folder named groovy-core
Change directories ( cd ) into your groovy-core version of the directory.
5.3. Copy Groovy
Clone/copy your forked repository from your own GitHub account to your local system, then check which version of the Java runtime environment you have.
git clone https://github.com/xxxxxx/groovy-core.git
cd groovy-core
java -version
If your java version is earlier than 1.6 you might not be able to do much testing. If it’s recent then change directories into the groovy-core folder.
5.4. Check Your Installation
To make sure you can build and test your Groovy version, try to build just the Groovy document suite.
-
bash ./gradlew asciidocAll on Linux/Ubuntu
-
gradlew asciidocAll on Windows
-
./gradlew asciidocAll for Apple
Your sample log might look like this :
Sample Log
martin@martin-EC548AA-ABU-a1128-uk:/media/martin/LINKS/groovy-core/groovy-core$ bash ./gradlew asciidocAll To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.12/userguide/gradle_daemon.html. :buildSrc:clean UP-TO-DATE :buildSrc:compileJava :buildSrc:compileGroovy :buildSrc:processResources UP-TO-DATE :buildSrc:classes :buildSrc:jar :buildSrc:assemble :buildSrc:compileTestJava UP-TO-DATE :buildSrc:compileTestGroovy UP-TO-DATE :buildSrc:processTestResources UP-TO-DATE :buildSrc:testClasses UP-TO-DATE :buildSrc:test UP-TO-DATE :buildSrc:check UP-TO-DATE :buildSrc:build Using Java from /usr/lib/jvm/java-7-openjdk-i386/jre (version 1.7.0_55) Detected development environment :asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-closures.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-differences-java.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-domain-specific-languages.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-gdk.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-getting-started.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-introduction.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-metaprogramming.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-object-orientation.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-operators.adoc asciidoctor: WARNING: src/spec/doc/design-pattern-abstract-factory.adoc: line 1: section title out of sequence: expected level 2, got level 4 asciidoctor: WARNING: design-pattern-in-groovy.adoc: line 52: section title out of sequence: expected level 2, got level 3 Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-iterator.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-loan-my-resource.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-null-object.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-pimp-my-library.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-proxy.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-singleton.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-state.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-strategy.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-template-method.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-visitor.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/grape.adoc asciidoctor: WARNING: grape.adoc: line 28: section title out of sequence: expected levels 0 or 1, got level 2 asciidoctor: WARNING: grape.adoc: line 105: section title out of sequence: expected levels 0 or 1, got level 2 Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/guide-integrating.adoc asciidoctor: WARNING: guide-integrating.adoc: line 11: section title out of sequence: expected levels 0 or 1, got level 2 Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/index.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/invokedynamic-support.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/license-contributors.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/template-engines.adoc asciidoctor: WARNING: subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc: line 1: section title out of sequence: expected level 2, got level 3 asciidoctor: WARNING: template-engines.adoc: line 145: section title out of sequence: expected level 2, got level 3 Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyc.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyconsole.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovydoc.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyeclipse.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovysh.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-ide.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/version-scheme.adoc Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/windows-nsis-installer.adoc :asciidoctorAssets :asciidocAll :groovy-ant:asciidoctor SKIPPED :groovy-ant:asciidoctorAssets :groovy-ant:asciidocAll UP-TO-DATE :groovy-bsf:asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc :groovy-bsf:asciidoctorAssets :groovy-bsf:asciidocAll :groovy-console:asciidoctor SKIPPED :groovy-console:asciidoctorAssets :groovy-console:asciidocAll UP-TO-DATE :groovy-docgenerator:asciidoctor SKIPPED :groovy-docgenerator:asciidoctorAssets :groovy-docgenerator:asciidocAll UP-TO-DATE :groovy-groovydoc:asciidoctor SKIPPED :groovy-groovydoc:asciidoctorAssets :groovy-groovydoc:asciidocAll UP-TO-DATE :groovy-groovysh:asciidoctor SKIPPED :groovy-groovysh:asciidoctorAssets :groovy-groovysh:asciidocAll UP-TO-DATE :groovy-jmx:asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-jmx/src/spec/doc/jmx.adoc :groovy-jmx:asciidoctorAssets :groovy-jmx:asciidocAll :groovy-json:asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-json/src/spec/doc/json-userguide.adoc :groovy-json:asciidoctorAssets :groovy-json:asciidocAll :groovy-jsr223:asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc :groovy-jsr223:asciidoctorAssets :groovy-jsr223:asciidocAll :groovy-nio:asciidoctor SKIPPED :groovy-nio:asciidoctorAssets :groovy-nio:asciidocAll UP-TO-DATE :groovy-servlet:asciidoctor SKIPPED :groovy-servlet:asciidoctorAssets :groovy-servlet:asciidocAll UP-TO-DATE :groovy-sql:asciidoctor SKIPPED :groovy-sql:asciidoctorAssets :groovy-sql:asciidocAll UP-TO-DATE :groovy-swing:asciidoctor SKIPPED :groovy-swing:asciidoctorAssets :groovy-swing:asciidocAll UP-TO-DATE :groovy-templates:asciidoctor Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc :groovy-templates:asciidoctorAssets :groovy-templates:asciidocAll :groovy-test:asciidoctor SKIPPED :groovy-test:asciidoctorAssets :groovy-test:asciidocAll UP-TO-DATE :groovy-testng:asciidoctor SKIPPED :groovy-testng:asciidoctorAssets :groovy-testng:asciidocAll UP-TO-DATE :groovy-xml:asciidoctor SKIPPED :groovy-xml:asciidoctorAssets :groovy-xml:asciidocAll UP-TO-DATE BUILD SUCCESSFUL Total time: 5 mins 22.43 secs
5.5. Success ?
If your command log looks something like the above, then you have a valid Groovy installation, and you’ve also constructed a fresh local copy of the Groovy documentation.
You can check your local copy to see if it looks good. Using the example above, you should have an index.html page located in file:///media/martin/LINKS/groovy-core/target/asciidoc/index.html though your actual address of the index.html file will differ a little. Enter your own address as a browser address, then you should see this :
As you update documents, you may need to see how it looks. Following the previous steps, you can do it using the ./gradlew asciidocAll command, then open the Groovy Index page and navigate to the topic you’ve updated.
6. Choose Where To Contribute
6.1. Identify Potential Topics
Do you have a special interest, or know some areas where you have some knowledge or where your skills may be useful ? There are many areas where your expertise can be put to good use. Here’s one idea.
Open the Groovy Documentation Tree. There are a large number of document files, one for each core component and each separate sub-project extension within Groovy. These are simple text file (no funny stuff) in a markup syntax called asciidoc. Document files end with .adoc.
| This link is for documents in the core system. There are matching trees for each sub-project like json, xml, swing, etc. |
For an example, let’s look at one document named core-domain-specific-languages.adoc. Confirm you are signed into GitHub then click the above link to see our live documentation tree.
You’ll be taken into the document set for domain specific languages in the live Groovy code base - not your own GitHub version.
| Remember that Groovy development is dynamic and changes daily. The copy you took will become dated and will not have newer changes, additions, etc. so it’s more accurate to review live Groovy when deciding what you’d like to do. |
6.2. Drill Down
See that module named core-domain-specific-languages.adoc ? Click on that filename.
If you review core-domain-specific-languages.adoc, you’ll see a button marked Raw at the top right. Click Raw to see the actual plain text markup within the core-domain-specific-languages.adoc file. It starts like this:
= Domain-Specific Languages
== Command chains
Groovy lets you omit parentheses around the arguments of a
method call for top-level statements. ``command chain'' feature extends this by allowing us to chain such
parentheses-free method calls, requiring neither parentheses around arguments, nor dots between the chained calls.
The general idea is that a call like `a b c d` will actually be equivalent to `a(b).c(d)`. This
also works with multiple arguments, closure arguments, and even named arguments. Furthermore, such command chains can
also appear on the right-hand side of assignments. Let's have a look at some examples
supported by this new syntax:
[source,groovy]
---------------------------------------------------------------------------------------------------------------
// equivalent to: turn(left).then(right)
turn left then right
. .
...
Then if you look below, you can see different topics like :
== Operator overloading
(TBD)
== Script base classes
(TBD)
== Adding properties to numbers
(TBD)
Since these titles are marked as (TBD) or To Be Done they need some work.
6.3. Ready To Start ?
So now you know how and where to look, you can review our Groovy documents depending on your area of interest. Find a subject title marked something like +== Operator overloading
(TBD) + in one of our .adoc files, or whatever takes your fancy.
Then after you decide how/where to donate, register your interest in that area and claim it as yours. Read on to learn how you do that.
7. Stand And Declare
7.1. Declare Your Interest
To let us know you’re working on a topic, it’s useful to put your id, like nickname, date, etc., next to your topic. Edit the .adoc file directly in your own online copy of groovy-core to insert your id. After that, save the document, comment and commit the change. Finally, you issue a PULL request to the Groovy admins to merge your amendment back into the Groovy code base from your GitHub account.
This way you stake a claim to a particular topic and everyone knows it’s what you’re working on. If someone else wants to work on that topic, they’ll see your id and should avoid it.
| After you are finished writing, editing, updating and placing your changes back into the Groovy code base, you will need to remove your id. |
7.1.1. Annotate The Topic Document
Here’s a demo we did earlier. Notice the line +==== MarkupBuilder
(TBD) - assigned to JNorthr 1July14+ assigned to one of our documentation team ?
You need to do the same, to an .adoc document in your own GitHub copy. Look in a folder named something like ./groovy-core/groovy-core/src/spec/doc to see where your topic has been discussed. Then edit it, adding your id and, if necessary, save as plain text format using the UTF-8 character set.
| We do not have a procedure yet for new topics. Can you suggest one ? |
If you’ve cloned/copied groovy-core to your local system, you can do the same thing this way :
cd ./groovy-core/groovy-core/src/spec/doc
edit core-domain-specific-languages.adoc
// add your id on the topic you'll document
save core-domain-specific-languages.adoc as UTF-8
7.2.  You must ask Groovy admin to merge your changes into Groovy from your own GitHub account. Go to your own GitHub home page and find the repository you copied from Groovy.
A merge is known as a PULL request because you are asking Groovy admin to PULL your changes back into the Groovy codebase.
Click the PULL button to see the next panel.
| Only one PULL request can be issued for each branch modification. |
Click the New Pull Request button.
You will need to enter a comment and title. It helps Groovy admin to understand what’s going on.
7.3. Review Your Submission
You can review your submitted details here. See where your commit statement appears ? Under that, you can see your actual changes, the line in PINK was removed and replaced by the line shown in GREEN. ( This sample is from a more recent declaration ).
8. Asciidoctor Markup, A Review
This Groovy document, and most others, are written with asciidoctor. Each time Groovy is rebuilt, a fresh version of all .adoc files are too. Visit our Success topic above to learn how to review your own Groovy documents.
Here’s an overview of the Asciidoctor Syntax. It’s a simple markup style that comes with a Ruby Gem. The markup syantax is based on an earlier effort named asciidoc and you can read more about that original version of Asciidoc here. Review a style guide here.
8.1. Why Use Asciidoctor ?
IN these days of fast paced application development, it’s GR8 to have a simple markup language and tool to write stuff. The asciidoctor tool is a quick performing ruby gem we can use to write up documentation and reference materials. We can write them quickly, then translate them into either HTML or Docbook output, and we can do this outside the Groovy development environment. Of course, it’s an automatic feature of full Groovy build, but on a small scale, it’s much easier to see how things look when built locally before the full-build stage.
8.2. Install Your Own Doctor
If you still wish to donate some expertise, but want to avoid a full Groovy install, it’s possible to install the asciidoctor tool on your own system.
In a terminal console, try gem install asciidoctor using the asciidoctor toolchain guide here.
Then you can write a simple sample plain text file using an editor ( without funny stuff or markup). Follow the syntax guide above. Then when you’re ready, you can do this from a command line like we did here to create this document. This text file is named groovy-contributions.adoc and and it was saved with a UTF-8 character encoding.
After asciidoctor ran, we had an output file named groovy-contributions.html in the same directory as the .adoc file. Since the
CSS stylesheet is embedded in the .html document, you can view this result right away, though images and javascript stuff may not be in the expected place.
martin@EC548A:~/Desktop$ asciidoctor groovy-contributions.adoc
If you find you’ve created something useful, check out our mailing lists to see how you can donate it.
| Converting asciidoctor markup to html - will give Groovy people an overview of other possibilities. |
9. Tag Annotations
Documents benefit from the inclusion of code samples. Live tests that are part of a typical Groovy build are ideal candidates. We know that if a build succeeds, then all it’s tests were successful too. Therefore samples from live tests can improve our documents.
Before we get into the topic of test cases, here’s a heads-up on how we do it using some asciidoctor features.
9.1. Asciidoctor Includes and Tags
Asciidoctor can identify parts of files for inclusion. Use the include statement to insert source material from another file. The include syntax offers a nice way to choose a piece of the file to include. The tag declaration identifies the piece.
| tag names follow a convention of {name of script}_{name of method}_{incrementing number of this test within all tests}[] |
Given an asciidoctor declaration like this :
=== Sample Asciidoc BuilderSupportTest Tag [source,groovy] .BuilderSupportTest.groovy Listing ---- include::BuilderSupportTest.groovy[tags=BuilderSupportTest_add_node_with_value_object4] ----
would only insert source statements between the BuilderSupportTest_add_node_with_value_object4 tag start and end as follows :
from this :
// tag::BuilderSupportTest_add_node_with_value_object4[] // simple node with one attribute def sb3 = new BuilderSupportTest() def node3 = sb3.foo(name:'value') // node type 3 creation with map as name/value pair assert sb3.log == ['cn3','foo', 'name','value', 'nc',null,'x'] // end::BuilderSupportTest_add_node_with_value_object4[]
| // characters identify the remainder of a line as remarks. |
Asciidoctor tags are simply remarks / comments and so are invisible at build time. They’re declared in pairs as a tag set. The tag keyword preceeds the tag name BuilderSupportTest_add_node_with_value_object4 followed by the asciidoc required tag ending of []
// tag:: says start using text after this line.
// end:: says stop using text before this line.
Does this make sense ? It’s possible to grab some of a live test and insert it into our document. It’s always a valid example 'cos the build succeeded
Ok, let’s review test cases next.
10. Examine Test Cases
10.1. Review Current Tests
Review the Test Case folder. There may already be tests that cover your area of interest. Some were written before tag standards came into existence. It might be as simple as adding asciidoctor tags around a test method.
10.1.1. Change Known Test Cases
Here’s an existing test case from groovy-core/src/spec/test/builder/CliBuilderTest.groovy :
Typical class comments preceed the class declaration with author attribution :
/**
* Tests for CliBuilder. The tests directly in this file are specific
* to CliBuilder. Functionality in common with other Builders
* is tested in the parent class.
*
* @author Groovy Documentation Community
*/
Earlier test cases did not use GroovyTestCase as a basis, though more recent test cases do :
class CliBuilderTest extends GroovyTestCase {
void testObjectNotDefined() {
// tag::clibuilder_nullobject1[]
CliBuilder clibuilder;
// clibuilder should be null when not initialized
assert clibuilder == null;
// end::clibuilder_nullobject1[]
} // end of method
CliBuilder clibuilder;
// clibuilder should be null when not initialized
assert clibuilder == null;
| The assert statement should have a remark before it. It should explain say why the test should succeed - not why it would fail |
10.2. Add New Test Cases
It’s outside the scope of this document, though if you feel something is missing in our test coverage, please raise a question. Our mailing lists are an ideal place to ask questions and receive suggestions about how you can contribute new test cases. Everyone says more tests improve product quality. Can you think of any tests we missed ?
10.2.1. Copyright Notice
It’s always useful to identify the license terms for use with any asset you create or amend. A copyright statement does just that. Here’s a sample copyright often used when doing test cases :
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
11. How To Write Documentation
Review current Groovy documents to gain an understanding of how it’s written and what sort of content it has. Look at this page about Json. It uses our latest document standards. Now you know about tags you can appreciate how test samples are picked from external sources.
11.1. Our Suggestions
An introduction describes the purpose of the document. Major topical areas are started by level one headings. More detailed text pieces would be started with level two headings.
Follow guidelines for version 1.4.0 of Asciidoctor.
11.2. Refer To Testcase Tags
As per our notes above about tags, write your document to include external text when appropriate.
[source,groovy] .Test.groovy Listing ---- include::Test.groovy[tags=Test_add_new_json_node_with_value_7] ----
11.3. Images Go Where ?
Images of GUI panels improve understanding and act as a powerful aid to learn new and/or difficult concepts.
Groovy-core images and GUI related stuff can be put in the groovy-core/src/spec/assets/img folder. Sub-projects have their own image folders, so groovy-core/subprojects/groovy-servlet/src/spec/assets/img could keep images if a document concerns servlets.
| Some assets/img folders do not exist and must be created. |
Please try to keep the size of images small rather than use a very large image then ask asciidoctor to re-scale it smaller. This improves page load times for end users.
12. Review Output
After making changes, adding new features, images, external links, etc., it’s useful to review how it all looks on your own local system. If things don’t work out, it’s easier to fix than after promotion.
12.1. Regen Groovy Docs
First, change directories to the groovy-core directory created in Copy Groovy step.
~/.gradle $ cd /media/martin/LINKS/groovyCore/groovy-core
/media/martin/LINKS/groovyCore/groovy-core $ ./gradlew asciidocAll
To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.12/userguide/gradle_daemon.html.
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
:buildSrc:processResources UP-TO-DATE
:buildSrc:classes UP-TO-DATE
:buildSrc:jar UP-TO-DATE
:asciidoctor
Rendering /media/martin/LINKS/groovyCore/groovy-core/src/spec/doc/core-closures.adoc
To rebuild your version of Groovy documents, try this. Run one of these commands depending on your operating system:
-
bash ./gradlew asciidocAll on Linux/Ubuntu
-
gradlew asciidocAll on Windows
-
./gradlew asciidocAll for Apple
12.2. Review Generated Results
If your command worked ok, you’ll have a fresh local copy of the Groovy documentation.
You can check your local copy to see if it looks good. After a regen, there should be index.html page located in ./groovy-core/groovy-core/target/asciidoc/index.html ( your actual address may differ ).
Enter your own address in a browser to see this :
As you modify documents, you can now see how they look. Just navigate to the topic you’ve updated and enjoy the fruits of your efforts
13. Cleanup
Ok, we have everything in place. All our changes are good-to-go so now they can go back to groovy-core
13.5. Remove Your Interest Id
Follow the directions given in Stand And Declare to remove your id marker.
13.6. Your Merge Request
13.6.1. Groovy PULL Requests
In a browser, enter https://github.com/apache/incubator-groovy to see the groovy-core home page in GitHub. It’s where we can get to the feature to ask our changes to be merged.
Take a look here. See Pull Request 24 ? This is where you can see how many other PULL requests are open, waiting to be done. Clicking Pull Requests gives you the next view. The New pull request button is there
13.6.2. PULL The Other One
These are the current PULL requests for Groovy. Notice how each request has a title ? It’s important to provide some idea about what a request will do.
As this example is about adding new documentation, click the New pull request button.
Pick a release to donate to. Typically, this would be the master branch, though if your work is for a future release, you could pick a more relevant branch.
Click the branch title where your request should go.
For this example, we’ll donate our work to release 2.4.0-beta-1. From this view, we can also see what’s going into, or will be removed from this release. See the Create pull request button ? Click that.
13.6.3. Do The Deed
The Groovy admins use info from this view. Include a title for your request. Put some comments in too to start the thread of conversation about this donation. Click Create Pull request. You should receive a pull request number and the Pull Request 24 count from the home page will become 25 when your request is confirmed.
14. A Waiting Game
Now, you’ve submitted your request to Groovy admins and received a PULL / merge request number.
14.1. Track Your Changes
Again, do the same thing we did to create the request.
To follow the progress of your request, in a browser, enter https://github.com/apache/incubator-groovy to see the groovy-core home page in GitHub.
Look again. This is where you can saw how many other PULL requests were open, waiting to be done, including yours. Clicking Pull Request took you to the next page for that view.
14.1.1. The PULL List
Here are waiting PULL requests for Groovy. As this example is about adding new Builder Documentation, it was given a request number 488. Look down the page to find it.
To learn more about any request, click a request title. GitHub opens a request details view as seen below.
Everything about a request is shown there. It’s the data Groovy admins work with.
Queries might be raised about something in your submission. These comments may require further improvements and/or changes to your submission. It’s a bit like a message thread where interested people can follow progress of a submission, make suggestions, etc.
| Green marks confirm the success of a request. Click the icon to see how the request was processed. |
At the right of each entry are comment icons with the number of comments made about each request. Click the icon to get the following view.
14.2. Verify Success
| This step is optional |
PULL requests become merge requests upon acceptance. Each merge is given a task number, for this example our merge / PULL request 488 is assigned task number 2093. It was merged into the master core branch of Groovy. Click 488/merge to drill down into the details.
The next view has specific details about every build attempt made for this request..
Here we can see that our request 488 has been executed a number of times. Each time it received another task execution number. The most recent task was 2093 marked with Green mark. That means Success !
| Task 1968 failed as there is a red |
For even more detail, we can drill down again into task messages by clicking the request number. Click task Tests passed 17761 for next view.
Ok, so here is the good news ! Request was successful. It passed all 17,761 tests.
Oops There was an error !
As seen above in the task execution list, task 1968 had bad news. Clicking 1968 displays this view.
This needed some work on the part of the submitter to remedy the failure. The continuous integration server then scheduled and re-executed the revised submission.


To learn language C and memerize some important points better, I decided to start a blog to keep some difficult and tricky points I met in the study of C.
The compilation of c
Usually, in the terminal, we use the command
gcc -Wall -std=c99 -o exefile_name .cfile_name
to compile the language.
Note:
- There is no mid file .o because it uses -o the compile directly.
- -Wall means shows all warnings after the compilation.
- -std=c99 means the version of C is C99 which is an old version replaced by C11 in 2011.
- the positions of exefile_name and .cfile_name cannot be changed. Otherwise gcc will not find the input file.
We use /* … */ to comment in C. e.g. :
/************************************************/
/* Converts a Fahrenheit temperature to Celsius */
/* *Name: celsius.c* */
/* *Author: K. N. King*/
/* *September 11, 2017 ***************************/
Three standard I/O in
– stdin (from keyboard to screen terminal)
– stdout (terminal screen)
– stderr (terminal screen, it will display the error)
The return value in the end of main is the status code which indicates that the program is already finished.
The use of define: # define a b (define b as a/use a to replace b) and this is macro definition
The use of % and &:
The identifiers in C:
start with a letter or underscore
case sensitive
printf:
In the case printf(“%d %d”, a); a is an int, it will print a’s value and print the meaningless content.
In the case printf(“%d”, a, b); it will only print the value of a.
We cannot use printf(“%f”, a); a is an int to change the type of the output since the output will become meaningless.
The conversion specification in the printf
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main(void) {
int i;
float x;
i = 40;
x = 839.21f;
printf("|%d|%5d|%-5d|%5.3d|\n", i, i, i, i);
printf("|%f|%10.3f|%10.3e|%-10g|\n", x, x, x, x);
return 0;
}
Result:
1
2
|40| 40|40 | 040|
|839.210022| 839.210| 8.392e+02|839.21 |
difference between %f and %e:
%f display the decimal format, in the %.pf, p means 保留几位小数.
%e display the exponential format, same p’s function.
%g display either exponential or decimal format, depending on the size of the number.
”%-5d” means 靠右对齐 and 显示五位,不足的用empty space 代替.
If we want to print “, we use \”, for example printf(“\“hello\””) ; prints “hello”.
scanf:
& in the scanf means the memory unit address of the variable, it pointing to the memory address.
The return value of scanf:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#define FREEZING_PT 32.0f
#define SCALE_FACTOR (5.0f / 9.0f)
int main(void) {
float fahrenheit, celsius;
for (;;) {
printf("Enter Fahrenheit temperature (non-number to quit): ");
if (scanf("%f", &fahrenheit) == 1) f
celsius = (fahrenheit - FREEZING_PT) * SCALE_FACTOR;
printf("Celsius equivalent: %.1f\n", celsius);
}
else break;
}
return 0;
}
output:
1
2
3
4
5
6
7
8
Enter Fahrenheit temperature (non-number to quit): 8
Celsius equivalent: -13.3
Enter Fahrenheit temperature (non-number to quit): 0
Celsius equivalent: -17.8
Enter Fahrenheit temperature (non-number to quit): 1 2
Celsius equivalent: -17.2
Enter Fahrenheit temperature (non-number to quit): Celsius equivalent: -16.7
Enter Fahrenheit temperature (non-number to quit): p
The first two cases are normal. In the third case, user input two numbers but scanf only has one place to store. so it displays the output in the next loop directly through the remaining input in the last function which is 2 in this case. In the last case, the return value of scanf is 0, so the if statement terminates the loop.
The input of several contents
1
2
3
4
5
6
7
8
#include <stdio.h>
int main() {
int i,j;
float x, y;
scanf("%d%d%f%f", &i, &j, &x, &y);
printf("%d %d %f %f",i,j,x,y);
return 0;
}
result:
1
2
3
4
5
6
7
8
9
10
11
Input: 1 -20 .3 -4.0e3
ouput: 1 -20 0.300000 -4000.000000
input:1
n-20
.3
-4.0e3
output:1 -20 0.300000 -4000.000000
input: 1-20.3-4.0e3
output:1 -20 0.300000 -4000.000000
In the last case, after read in the number 1, scanf finds the - and - can not appear inside an number, so puts it back can store 1 in the variable i. After finding the second number -20, scanf finds ., and the . can not appear inside the number. By this kind of way, scanf successfully reads four numbers.
The format ieee 754 of binary:
Three parts of ieee 754:
- sign (1 bit)
- exponent (8 bits)
- fraction(23 bits)
Expression:
side effect in assignment:
when assigning int i = 72.99f;, Since the variable i is int, the .99 will be discarded directly. This is called the side effect of assignment.
After computing the value, the variable i is also changed, this is side effect.
i += j += k is equal to i += (j+=k)
difference between i++ and ++i:
i++: use i first and plus one
++i: plus one first and then use i
1
2
3
4
5
6
7
8
9
#include <stdio.h>
int main() {
int i = 1;
int a = 3;
printf("%d\n", (i++) + a);
i = 1;
printf("%d\n", (++i)+a);
return 0;
}
result:
1
2
4
5
The lvalue(left value) in the assignment is an object stored in memory which cannot be a number or a character.
The expression can be a statement without lvalue but after it is calculated, it will be discarded. so it is useful only when side effect works on.


Bratislava Marathon
Bratislava SVK
Website: www.bratislavamarathon.com/?s=marathon
Race Winners
(14 runnings)
01
Apr 2012 27 Mar
2011
28 Mar
2010
29
Mar
2009
30
Mar
2008
01
Apr
2007
02
Apr 2006
Note: Racen currently known as CSOB Bratislava City Marathon.
07
Apr 2018
2:37:17
Slawomir Gawlik (POL)
3:00:27
Barbora Novakova (CZE)
08
Apr 2018
2:22:16
Jiri Cipa-2
2:58:41
Kristína Néc Lapinova (SVK)
02
Apr 2017
2:29:44
Jozef Urban (SVK)
2:51:49
Michaela Mertova (CZE)
03
Apr 2016
2:27:41
Jiri Cipa (CZE)
3:12:39
Zsofia Bodi (HUN)
29
Mar 2015
2:17:18
Hosea Tuwei Kiplagat (KEN)
2:35:35
Hellen Kimutai Chepkosgei (KEN)
06
Apr 2014
2:18:22
Joel Maina Mwangi (KEN)
2:42:55
Alice Chepkemboi Kibor (KEN)
24 Mar
2013
2:18:33
Isaac Cheruiyot Chesiny (KEN)
2:51:42
Lilian Chepkosgei Koech (KEN)
2:21:09
Micah Kiplagat Samoei (KEN)
2:42:41
Lucy Wambui Murigi (KEN)
2:22:09
Ashenafi Erkolo (ETH)
2:45:30
Lilian Chepkosgei
Koech-2
2:27:38.4
Edwin Kibowen Kiptanui (KEN)
2:51:15.7
Lilian Chepkosgei Koech (KEN)
2:21:40
Aleksey Harychenko (BLR)
2:50:21
Judit Nagy (HUN)
2:19:42
Vasiliy Remschuk (UKR)
2:56:29
Katalin Farkas (HUN)
2:25:09
Artur Blasinski (POL)
2:56:22
Dana Janeckova (SVK)
2:33:08
Bogdan Dziuba (POL)
3:10:43
Andrea Beresova (SVK)
Most Wins
Men
2 Women
2
Jiri Cipa (CZE)
2016,2018
Lilian Chepkosgei Koech (KEN)
2010-11
Prize Money (ADR
qualified runners)Year Men Women Total
2017 640 320 960
2016 625 340 965
2015 6,040 6,370 12,410
2014 5,685 5,410 11,095
2013 6,625 5,940 12,565
....
2011 6,725 5,070 11,795
2010 6,140 3,930 10,070
2009 5,845 3,560 9,405
2008 7,660 3,395 11,055
2007 5,800 2,800 8,600
Sums $51,785 $37,135 $88,920
Race Time Bias (sec/km) Year Men Women 2012 +6.0 n/c .... 2007 +0.4 n/c Avgs +3.2 n/c
Competitive Level (1990-date)
Year Men Women 2012 47 n/c 2011 n/c 11
Quality Performances through 2019
Men <2:18 2 <2:19 5 <2:20 6 Women <2:36 1 <2:38 1 <2:40 1 <2:42 1 <2:44 4
Dunajsky (Danube) Marathon
Bratislava SVK
Website: www.gates96.com/user/donaumarathon
Race Winners
(11 runnings)
28 Apr
2001
2:19:16
2:58:23
29 Apr
2000
2:18:23
2:52:55
24 Apr
1999
2:18:21
2:52:46
25 Apr
1998
2:16:57
2:49:56
26 Apr
1997
2:18:01
2:42:40
11 May
1996
2:18:55
2:51:48
13 May 1995
2:19:07
2:41:26
28 May
1994
2:18:34
2:43:00
15 May
1993
2:24:16
2:54:24
30 May
1992
2:29:40
2:46:41
25 May
1991
2:19:19
2:53:57
Note: 1991 was the inaugural year. This marathon started in Bratislava, had its turnaround point in Hainberg AUT,
and finished in Bratislava. The 2002 race was cancelled due to lack of sponsorship. The course was first certified
in 1996 for the 1997 race.
Nikolay Antonenko-3
Anna Balosakova-3
Nikolay Antonenko-2
(nc)
Anna Balosakova-2
(nc)
Nikolay Antonenko (UKR)
Anna Balosakova (SVK)
Boubker El Afoui (MAR)
Andrea Beresova (SVK)
Adam Przybysz (POL)
(nc)
Galina Yatsenko (UKR)
(nc)
Dariusz Kaczmarski (POL)
Ludmila Melicherova-2
Viktor Vikhristenko (UKR)
(nc)
Ludmila Melicherova (SVK)
(nc)
Viktor Kornienko (UKR)
Irina Yagodina (UKR)
Aleksandr Makodzeba (UKR)
(nc)
Karina Leutner (AUT)
(nc)
Attila Barus (SVK) (nc)
Lyubov Bereznik (RUS)
(nc)
Vlastimil Bukovjan (CZE)
Vlasta Rulcova (CZE)
(nc) => Slovak championship
2000 Vaclav Zupa was the Slovak champion (4th place, 2:26:19)
1997 Stefan Lehen was the Slovak champion (11th place, 2:27:56)
1997 Katarina Jedinakova was the Slovak champion (5th place, 3:00:14)
1995 Jan Kalavsky was the Slovak champion (8th place, 2:27:02)
1993 Lubos Cesnek was the Slovak champion (3rd place, 2:27:42)
1993 Janka Hudakova was the Slovak champion (4th place, 3:10:03)
1992 Alena Sladka was the Slovak champion (3rd place, 3:03:45)
Most Wins (1991-2001)
Men
3
Nikolay Antonenko (UKR)
1999-2001
Women
3
Anna Balosakova (SVK)
1999-2001
Prize Money
(ADR qualified runners)
No prize money has been awarded at this race according to available information.
Race Time Bias (sec/km)
Year Men Women 1998 -0.1 n/c Competitive Level (1990-date)
Insufficient data to calculate the competitive level.
Quality Performances
Men <2:17 1 <2:18 1 <2:19 10 <2:20 20 Women <2:42 1 <2:44 4 <2:46 4 <2:48 6 <2:50 9
Last Updated on 10 Apr 2019 mp
Contributors: Juraj Gasparovic (8), Franco Civai (1)


- User Experience Design, User Interface Design, User Centred Design, Interaction Design, Graphic Design-
Find Out MoreMy name is David Leen and I am from County Kerry, in Ireland. I have a Bachelor of Science degree in Digital Media Design, where I graduated with first-class honours, from the University of Limerick. My studies have equipped me for a role in the design industry and areas such as UX/UI Design, Interaction Design and Graphic Design, to name a few.
I possess a good working knowledge of many industry leading software applications such as the Adobe Suite, as well as having video and audio editing/production experience. I also have acquired knowledge in user centric design, sociology and user research. I’ve developed an excellent eye for detail due to the heavy demands of assignments and project deadlines, during my studies and in employment. I have experience working in a multimedia and digital media marketing company, as a digital media designer and video editor. My roles there, had me undertaking many responsibilities and different tasks, working on a variety of projects in the tourism and promotional sector. I’ve gained many transferable skills over the years, such as excellent team work, initiative, communication, time management and organisational skills.
My knowledge and skills have been shaped and enhanced over a number of years and I am eager to develop and add to them further. I feel an important aspect of design, is to follow a good design process. Good designs are not just the end product, but also the important steps taken along the way, that ensure the best possible outcome. I aim to utilise the skills and knowledge I have developed, to become a valuable design contributor and forge a successful career in the digital media and design industry.
Feel free to get in touch with me if you have any questions about me or my portfolio, or connect with me through LinkedIn.
+353 860611784


The Taste
They taste the best! That salty sea air brought right to your mouth with enchancing tea time! Lorem ipsum dolor sit amet consectetur, adipisicing elit. Cumque autem consectetur rem quidem, dicta ea nesciunt id inventore at quod numquam labore illo aut, eveniet blanditiis nemo et, modi harum! Lorem ipsum dolor sit amet consectetur adipisicing elit. Nulla commodi iste perspiciatis voluptas, quibusdam eaque ullam totam earum minus ea. Beatae aspernatur voluptatem officia repudiandae rerum numquam vitae nemo nesciunt. Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae corporis odio delectus fuga facilis, iusto cupiditate dolorum. Maiores deleniti dignissimos inventore, quisquam iste debitis quae? Itaque laudantium odio modi dignissimos.
The best thing I have ever eaten! -Everyone
About Pat and his Cookies
Pat is thrilled to share his cookies with you! What began as a coveted treat at his weekly dinners with friends is now available to the world! Lorem, ipsum dolor sit amet consectetur adipisicing elit. Doloremque aperiam quasi in voluptas eum, saepe quas quo commodi unde rerum molestias vero voluptates facilis nulla quae, tempora distinctio dolore eius!
Make your family happy with some cookies today!
Locations and Hours
-
Seattle
- 1243 Pike St
- Seattle, WA
- Hours: 6am-8pm
-<PHONE_NUMBER>
-
Tokyo
- 1243 South St
- Tokyo, Japan
- Hours: 6am-8pm
-<PHONE_NUMBER>
-
Dubai
- 1243 Tower St
- Dubai, UAE
- Hours: 6am-8pm
-<PHONE_NUMBER>
-
Paris
- 1243 Bread St
- Paris, France
- Hours: 6am-8pm
-<PHONE_NUMBER>
-
Lima
- 1243 Hot St
- Lima, Peru
- Hours: 6am-8pm
-<PHONE_NUMBER>


Restaurants
This is a website for all your restaurant searching needs in the burlington area. You can search for a restaurant or click on one that you're interested in on the list to the left.


{% extends "base.html" %} {% from "_formhelpers.html" import render_field %} {% block body %} Reco-Chan Github Repositry For this App Omedetou!
Hey {{user}} here are your recommendations ~


{% extends "site_base.html" %} {% load i18n %} {% block head_title %}Home{% endblock %} {% block body_class %}home{% endblock %} {% block site_brand %}{% endblock %} {% block navbar-toggler %}{% endblock %} {% block nav_items %}{% endblock %} {% block body_base %} {# no container as padding managed by section and fixed by media width #} Perseus Digital Library Scaife Viewer Browse Library Text Search Recent Changes week of March 5th changed passage notes and place annotations to appear in popovers implemented passage healing for references which do not resolve used a fallback API for word list widget when GVT does not contain the edition or work Previously... added text search widget in reader implemented lemma search for Greek changed widgets to fix heading while scrolling changed loaders to be consistent across site continued on-going effort to speed up all parts of the site improved styling of milestones, quote, bibl and gaps added Morpheus widget added filtering to word list widget based on selected word added CHS commentary widget implemented OpenID Connect authentication added popovers for versions in library (providing more metadata) improved Coptic support improved version selector in reader {% endblock %}
Browse Library Text Search


 Your job is to inspect papers of entrants and decide if they should be approved to enter your glorious country Arstotzka, denied the entry, or detained for falsifying their documents.
Game Layout
The top header section
- use the hamburger menu to show these instructions or logout
- use the violet sound controls to play / pause the background music
- username is printed on the right side
The dashboard section
- shows a list of previously saved users and their score (local storage)
allows to delete each record by clicking on the red bin icon next to it
- allows to create a new user through the input field
The game section consists of 4 quadrants
- upper left - Queue of entrants who wait for their turn to be inspected
- (upper mid) - Border between foreign country and Arstotzka. Has the megaphone icon to call the next entrant.
- upper right - Land of Arstotzka, UI shows current date and elapsed/remaining time for the day
- bottom left - Inspection window with current bulletin and the detain button
- bottom right - Inspection desk with approval/denial stamps
Game Flow
- In the dashboard section, choose on of the following
-
Pick from a list of existing users. (Click on the user to select.)
-
Create a new user by typing in a username in the form. (Type username in the input field. Confirm with 'enter' key.)
- In the game section
Start by reading the bulletin document. This is the base for your inspection and contains all the current rules of entry.
- read the bulletin by drag & dropping it from the inspection window to the inspection desk
- (optionally) put it back by drag & dropping from the inspection desk back to the inspection window
-
Click the megaphone icon to request a next entrant.
-
(Wait for the entrant to arrive at the booth)
-
Inspect papers presented by the entrant
- to see the details of each document, drag & drop it from the inspection window to the inspection desk
- to return papers back to the entrant, drag & drop it back from the inspection desk to the inspection window
-
Decide if entrant should be:
-
Approved to enter the country, acknowledging that:
- entrant has all the required papers (as per the bulletin)
- entrant comes from an accepted country (as per the bulletin)
- there is no discrepancy in any of the papers
- none of the required papers are expired (see today's date in the Arstotzka quadrant)
-
Rejected to enter the country on the basis of at least one of the following:
- entrant comes from a denied country (as per the bulletin)
- entrant is missing some of the required papers (as per the bulletin)
- some of the required papers are expired
-
Detained by the police on the basis of at least one of the following:
- there are discrepancies between the papers - different papers show different IDs, names, nations, weight or height
-
- If the decision is Approved or Denied
- drag & drop entrant's passport to the inspection desk
- bring in 'approved' & 'denied' stamps by clicking the white arrow
- align the passport's ENTRY VISA section with one of the stamps
- click on the stamp to stamp the passport - if well aligned, passport should show the resulting stamp
- drag & drop all the documents from the inspection desk back to the inspection window to give them back to the entrant
- If the decision is Detain
- click the red Detain button in the inspection window
-
Call the next entrant (go back to point 1)
You can see a blue timer in the Arstotzka quadrant. This shows the remaining / elapsed time of the current day. At the end of each day, you will see your score based on your performance. You will get 10 points for every correct decision. You will get -10 points for every wrong decision. However, you will get -20 points if you 'approve' an entrant who should have been 'detained'. If your score is less than 0, the game ends. If your score is more or equal to 0, you can either a) continue the game (reset the timer), b) save the game and end.


React.js
Supporting Architecture
By
Brandon Mason
/
@tlsft
Overview
Why reactive UIs?
React/Flux Philosophy
Understanding the data flow
Choosing a server technology
Demo
Resources
Questions
Not Covered
Implementation
Composition
Testing
Why Reactive UIs?
Reactive UIs are helpful for:
Content creation/management (gmail, trello)
Live data feeds (facebook, pinterest, instagram)
If you're publishing content:
company websites
marketing campaigns
blogs
...you probably don't need something like React.
1994
1994
Now-ish
MVC
Flux - Browser
Flux - Browser Detail
Flux - Browser/Server
Server Tech
Meteor
Firebase
???
Demo
http://react-chat.meteor.com/
RESOURCES
Demo on Github
More talk on React/Meteor
React-Meteor Package
Javascript Workshop
Questions?


| Top |
A GTask represents and manages a cancellable "task".
The most common usage of GTask is as a GAsyncResult, to
manage data during an asynchronous operation. You call
g_task_new()
in the "start" method, followed by
g_task_set_task_data()
and the like if you need to keep some
additional data associated with the task, and then pass the
task object around through your asynchronous operation.
Eventually, you will call a method such as
g_task_return_pointer()
or g_task_return_error()
, which will
save the value you give it and then invoke the task's callback
function (waiting until the next iteration of the main
loop first, if necessary). The caller will pass the GTask back
to the operation's finish function (as a GAsyncResult), and
you can use g_task_propagate_pointer()
or the like to extract
the return value.
Here is an example for using GTask as a GAsyncResult:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
typedef struct { CakeFrostingType frosting; char *message; } DecorationData; static void decoration_data_free (DecorationData *decoration) { g_free (decoration->message); g_slice_free (DecorationData, decoration); } static void baked_cb (Cake *cake, gpointer user_data) { GTask *task = user_data; DecorationData *decoration = g_task_get_task_data (task); GError *error = NULL; if (cake == NULL) { g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, "Go to the supermarket"); g_object_unref (task); return; } if (!cake_decorate (cake, decoration->frosting, decoration->message, &error)) { g_object_unref (cake); // g_task_return_error() takes ownership of error g_task_return_error (task, error); g_object_unref (task); return; } g_task_return_pointer (task, cake, g_object_unref); g_object_unref (task); } void baker_bake_cake_async (Baker *self, guint radius, CakeFlavor flavor, CakeFrostingType frosting, const char *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; DecorationData *decoration; Cake *cake; task = g_task_new (self, cancellable, callback, user_data); if (radius < 3) { g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_TOO_SMALL, "%ucm radius cakes are silly", radius); g_object_unref (task); return; } cake = _baker_get_cached_cake (self, radius, flavor, frosting, message); if (cake != NULL) { // _baker_get_cached_cake() returns a reffed cake g_task_return_pointer (task, cake, g_object_unref); g_object_unref (task); return; } decoration = g_slice_new (DecorationData); decoration->frosting = frosting; decoration->message = g_strdup (message); g_task_set_task_data (task, decoration, (GDestroyNotify) decoration_data_free); _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); } Cake * baker_bake_cake_finish (Baker *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), NULL); return g_task_propagate_pointer (G_TASK (result), error); } |
GTask also tries to simplify asynchronous operations that
internally chain together several smaller asynchronous
operations. g_task_get_cancellable()
, g_task_get_context()
,
and g_task_get_priority()
allow you to get back the task's
GCancellable, GMainContext, and I/O priority
when starting a new subtask, so you don't have to keep track
of them yourself. g_task_attach_source()
simplifies the case
of waiting for a source to fire (automatically using the correct
GMainContext and priority).
Here is an example for chained asynchronous operations:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
typedef struct { Cake *cake; CakeFrostingType frosting; char *message; } BakingData; static void decoration_data_free (BakingData *bd) { if (bd->cake) g_object_unref (bd->cake); g_free (bd->message); g_slice_free (BakingData, bd); } static void decorated_cb (Cake *cake, GAsyncResult *result, gpointer user_data) { GTask *task = user_data; GError *error = NULL; if (!cake_decorate_finish (cake, result, &error)) { g_object_unref (cake); g_task_return_error (task, error); g_object_unref (task); return; } // baking_data_free() will drop its ref on the cake, so we have to // take another here to give to the caller. g_task_return_pointer (result, g_object_ref (cake), g_object_unref); g_object_unref (task); } static void decorator_ready (gpointer user_data) { GTask *task = user_data; BakingData *bd = g_task_get_task_data (task); cake_decorate_async (bd->cake, bd->frosting, bd->message, g_task_get_cancellable (task), decorated_cb, task); } static void baked_cb (Cake *cake, gpointer user_data) { GTask *task = user_data; BakingData *bd = g_task_get_task_data (task); GError *error = NULL; if (cake == NULL) { g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, "Go to the supermarket"); g_object_unref (task); return; } bd->cake = cake; // Bail out now if the user has already cancelled if (g_task_return_error_if_cancelled (task)) { g_object_unref (task); return; } if (cake_decorator_available (cake)) decorator_ready (task); else { GSource *source; source = cake_decorator_wait_source_new (cake); // Attach @source to @task's GMainContext and have it call // decorator_ready() when it is ready. g_task_attach_source (task, source, G_CALLBACK (decorator_ready)); g_source_unref (source); } } void baker_bake_cake_async (Baker *self, guint radius, CakeFlavor flavor, CakeFrostingType frosting, const char *message, gint priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; BakingData *bd; task = g_task_new (self, cancellable, callback, user_data); g_task_set_priority (task, priority); bd = g_slice_new0 (BakingData); bd->frosting = frosting; bd->message = g_strdup (message); g_task_set_task_data (task, bd, (GDestroyNotify) baking_data_free); _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); } Cake * baker_bake_cake_finish (Baker *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), NULL); return g_task_propagate_pointer (G_TASK (result), error); } |
You can use g_task_run_in_thread()
to turn a synchronous
operation into an asynchronous one, by running it in a thread
which will then dispatch the result back to the caller's
GMainContext when it completes.
Running a task in a thread:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
typedef struct { guint radius; CakeFlavor flavor; CakeFrostingType frosting; char *message; } CakeData; static void cake_data_free (CakeData *cake_data) { g_free (cake_data->message); g_slice_free (CakeData, cake_data); } static void bake_cake_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { Baker *self = source_object; CakeData *cake_data = task_data; Cake *cake; GError *error = NULL; cake = bake_cake (baker, cake_data->radius, cake_data->flavor, cake_data->frosting, cake_data->message, cancellable, &error); if (cake) g_task_return_pointer (task, cake, g_object_unref); else g_task_return_error (task, error); } void baker_bake_cake_async (Baker *self, guint radius, CakeFlavor flavor, CakeFrostingType frosting, const char *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { CakeData *cake_data; GTask *task; cake_data = g_slice_new (CakeData); cake_data->radius = radius; cake_data->flavor = flavor; cake_data->frosting = frosting; cake_data->message = g_strdup (message); task = g_task_new (self, cancellable, callback, user_data); g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); g_task_run_in_thread (task, bake_cake_thread); g_object_unref (task); } Cake * baker_bake_cake_finish (Baker *self, GAsyncResult *result, GError **error) { g_return_val_if_fail (g_task_is_valid (result, self), NULL); return g_task_propagate_pointer (G_TASK (result), error); } |
Finally, g_task_run_in_thread()
and g_task_run_in_thread_sync()
can be used to turn an uncancellable operation into a
cancellable one. If you call g_task_set_return_on_cancel()
,
passing TRUE
, then if the task's GCancellable is cancelled,
it will return control back to the caller immediately, while
allowing the task thread to continue running in the background
(and simply discarding its result when it finally does finish).
Provided that the task thread is careful about how it uses
locks and other externally-visible resources, this allows you
to make "GLib-friendly" asynchronous and cancellable
synchronous variants of blocking APIs.
Cancelling a task:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
static void bake_cake_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable) { Baker *self = source_object; CakeData *cake_data = task_data; Cake *cake; GError *error = NULL; cake = bake_cake (baker, cake_data->radius, cake_data->flavor, cake_data->frosting, cake_data->message, &error); if (error) { g_task_return_error (task, error); return; } // If the task has already been cancelled, then we don't want to add // the cake to the cake cache. Likewise, we don't want to have the // task get cancelled in the middle of updating the cache. // g_task_set_return_on_cancel() will return %TRUE here if it managed // to disable return-on-cancel, or %FALSE if the task was cancelled // before it could. if (g_task_set_return_on_cancel (task, FALSE)) { // If the caller cancels at this point, their // GAsyncReadyCallback won't be invoked until we return, // so we don't have to worry that this code will run at // the same time as that code does. But if there were // other functions that might look at the cake cache, // then we'd probably need a GMutex here as well. baker_add_cake_to_cache (baker, cake); g_task_return_pointer (task, cake, g_object_unref); } } void baker_bake_cake_async (Baker *self, guint radius, CakeFlavor flavor, CakeFrostingType frosting, const char *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { CakeData *cake_data; GTask *task; cake_data = g_slice_new (CakeData); ... task = g_task_new (self, cancellable, callback, user_data); g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); g_task_set_return_on_cancel (task, TRUE); g_task_run_in_thread (task, bake_cake_thread); } Cake * baker_bake_cake_sync (Baker *self, guint radius, CakeFlavor flavor, CakeFrostingType frosting, const char *message, GCancellable *cancellable, GError **error) { CakeData *cake_data; GTask *task; Cake *cake; cake_data = g_slice_new (CakeData); ... task = g_task_new (self, cancellable, NULL, NULL); g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); g_task_set_return_on_cancel (task, TRUE); g_task_run_in_thread_sync (task, bake_cake_thread); cake = g_task_propagate_pointer (task, error); g_object_unref (task); return cake; } |
GTask's API attempts to be simpler than GSimpleAsyncResult's in several ways:
You can save task-specific data with g_task_set_task_data()
, and
retrieve it later with g_task_get_task_data()
. This replaces the
abuse of g_simple_async_result_set_op_res_gpointer()
for the same
purpose with GSimpleAsyncResult.
In addition to the task data, GTask also keeps track of the priority, GCancellable, and GMainContext associated with the task, so tasks that consist of a chain of simpler asynchronous operations will have easy access to those values when starting each sub-task.
g_task_return_error_if_cancelled() provides simplified
handling for cancellation. In addition, cancellation
overrides any other GTask return value by default, like
GSimpleAsyncResult does when
g_simple_async_result_set_check_cancellable()
is called.
(You can use g_task_set_check_cancellable()
to turn off that
behavior.) On the other hand, g_task_run_in_thread()
guarantees that it will always run your
task_func
, even if the task's GCancellable
is already cancelled before the task gets a chance to run;
you can start your task_func
with a
g_task_return_error_if_cancelled()
check if you need the
old behavior.
The "return" methods (eg, g_task_return_pointer()
)
automatically cause the task to be "completed" as well, and
there is no need to worry about the "complete" vs "complete
in idle" distinction. (GTask automatically figures out
whether the task's callback can be invoked directly, or
if it needs to be sent to another GMainContext, or delayed
until the next iteration of the current GMainContext.)
The "finish" functions for GTask-based operations are generally
much simpler than GSimpleAsyncResult ones, normally consisting
of only a single call to g_task_propagate_pointer()
or the like.
Since g_task_propagate_pointer()
"steals" the return value from
the GTask, it is not necessary to juggle pointers around to
prevent it from being freed twice.
With GSimpleAsyncResult, it was common to call
g_simple_async_result_propagate_error()
from the
wrapper function, and have
virtual method implementations only deal with successful
returns. This behavior is deprecated, because it makes it
difficult for a subclass to chain to a parent class's async
methods. Instead, the wrapper function should just be a
simple wrapper, and the virtual method should call an
appropriate _finish()
g_task_propagate_
function.
Note that wrapper methods can now use
g_async_result_legacy_propagate_error()
to do old-style
GSimpleAsyncResult error-returning behavior, and
g_async_result_is_tagged()
to check if a result is tagged as
having come from the
wrapper
function (for "short-circuit" results, such as when passing
0 to _async()
g_input_stream_read_async()
).
GTask * g_task_new (gpointer source_object
,GCancellable *cancellable
,GAsyncReadyCallback callback
,gpointer callback_data
);
Creates a GTask acting on source_object
, which will eventually be
used to invoke callback
in the current
thread-default main context.
Call this in the "start" method of your asynchronous method, and
pass the GTask around throughout the asynchronous operation. You
can use g_task_set_task_data()
to attach task-specific data to the
object, which you can retrieve later via g_task_get_task_data()
.
By default, if cancellable
is cancelled, then the return value of
the task will always be G_IO_ERROR_CANCELLED
, even if the task had
already completed before the cancellation. This allows for
simplified handling in cases where cancellation may imply that
other objects that the task depends on have been destroyed. If you
do not want this behavior, you can use
g_task_set_check_cancellable()
to change it.
source_object |
[allow-none][type GObject] | |
cancellable |
optional GCancellable object, |
[allow-none] |
callback |
[scope async] | |
callback_data |
user data passed to |
[closure] |
Since 2.36
void g_task_set_task_data (GTask *task
,gpointer task_data
,GDestroyNotify task_data_destroy
);
Sets task
's task data (freeing the existing task data, if any).
task |
the GTask |
|
task_data |
task-specific data. |
[allow-none] |
task_data_destroy |
GDestroyNotify for |
[allow-none] |
Since 2.36
void g_task_set_priority (GTask *task
,gint priority
);
Sets task
's priority. If you do not call this, it will default to
G_PRIORITY_DEFAULT
.
This will affect the priority of GSources created with
g_task_attach_source()
and the scheduling of tasks run in threads,
and can also be explicitly retrieved later via
g_task_get_priority()
.
Since 2.36
void g_task_set_check_cancellable (GTask *task
,gboolean check_cancellable
);
Sets or clears task
's check-cancellable flag. If this is TRUE
(the default), then g_task_propagate_pointer()
, etc, and
g_task_had_error()
will check the task's GCancellable first, and
if it has been cancelled, then they will consider the task to have
returned an "Operation was cancelled" error
(G_IO_ERROR_CANCELLED
), regardless of any other error or return
value the task may have had.
If check_cancellable
is FALSE
, then the GTask will not check the
cancellable itself, and it is up to task
's owner to do this (eg,
via g_task_return_error_if_cancelled()
).
If you are using g_task_set_return_on_cancel()
as well, then
you must leave check-cancellable set TRUE
.
task |
the GTask |
|
check_cancellable |
whether GTask will check the state of its GCancellable for you. |
Since 2.36
gboolean g_task_set_return_on_cancel (GTask *task
,gboolean return_on_cancel
);
Sets or clears task
's return-on-cancel flag. This is only
meaningful for tasks run via g_task_run_in_thread()
or
g_task_run_in_thread_sync()
.
If return_on_cancel
is TRUE
, then cancelling task
's
GCancellable will immediately cause it to return, as though the
task's GTaskThreadFunc had called
g_task_return_error_if_cancelled()
and then returned.
This allows you to create a cancellable wrapper around an
uninterruptable function. The GTaskThreadFunc just needs to be
careful that it does not modify any externally-visible state after
it has been cancelled. To do that, the thread should call
g_task_set_return_on_cancel()
again to (atomically) set
return-on-cancel FALSE
before making externally-visible changes;
if the task gets cancelled before the return-on-cancel flag could
be changed, g_task_set_return_on_cancel()
will indicate this by
returning FALSE
.
You can disable and re-enable this flag multiple times if you wish.
If the task's GCancellable is cancelled while return-on-cancel is
FALSE
, then calling g_task_set_return_on_cancel()
to set it TRUE
again will cause the task to be cancelled at that point.
If the task's GCancellable is already cancelled before you call
g_task_run_in_thread()
/g_task_run_in_thread_sync()
, then the
GTaskThreadFunc will still be run (for consistency), but the task
will also be completed right away.
task |
the GTask |
|
return_on_cancel |
whether the task returns automatically when it is cancelled. |
TRUE
if task
's return-on-cancel flag was changed to
match return_on_cancel
. FALSE
if task
has already been
cancelled.
Since 2.36
void g_task_set_source_tag (GTask *task
,gpointer source_tag
);
Sets task
's source tag. You can use this to tag a task return
value with a particular pointer (usually a pointer to the function
doing the tagging) and then later check it using
g_task_get_source_tag()
(or g_async_result_is_tagged()
) in the
task's "finish" function, to figure out if the response came from a
particular place.
Since 2.36
void g_task_report_error (gpointer source_object
,GAsyncReadyCallback callback
,gpointer callback_data
,gpointer source_tag
,GError *error
);
Creates a GTask and then immediately calls g_task_return_error()
on it. Use this in the wrapper function of an asynchronous method
when you want to avoid even calling the virtual method. You can
then use g_async_result_is_tagged()
in the finish method wrapper to
check if the result there is tagged as having been created by the
wrapper method, and deal with it appropriately if so.
See also g_task_report_new_error()
.
source_object |
[allow-none][type GObject] | |
callback |
[scope async] | |
callback_data |
user data passed to |
[closure] |
source_tag |
an opaque pointer indicating the source of this task |
|
error |
error to report. |
[transfer full] |
Since 2.36
void g_task_report_new_error (gpointer source_object
,GAsyncReadyCallback callback
,gpointer callback_data
,gpointer source_tag
,GQuark domain
,gint code
,const char *format
,...
);
Creates a GTask and then immediately calls
g_task_return_new_error()
on it. Use this in the wrapper function
of an asynchronous method when you want to avoid even calling the
virtual method. You can then use g_async_result_is_tagged()
in the
finish method wrapper to check if the result there is tagged as
having been created by the wrapper method, and deal with it
appropriately if so.
See also g_task_report_error()
.
source_object |
[allow-none][type GObject] | |
callback |
[scope async] | |
callback_data |
user data passed to |
[closure] |
source_tag |
an opaque pointer indicating the source of this task |
|
domain |
a GQuark. |
|
code |
an error code. |
|
format |
a string with format characters. |
|
... |
a list of values to insert into |
Since 2.36
gpointer
g_task_get_task_data (GTask *task
);
Gets task
's task_data
.
Since 2.36
GCancellable *
g_task_get_cancellable (GTask *task
);
Gets task
's GCancellable
Since 2.36
gboolean
g_task_get_check_cancellable (GTask *task
);
Gets task
's check-cancellable flag. See
g_task_set_check_cancellable()
for more details.
Since 2.36
gboolean
g_task_get_return_on_cancel (GTask *task
);
Gets task
's return-on-cancel flag. See
g_task_set_return_on_cancel()
for more details.
Since 2.36
GMainContext *
g_task_get_context (GTask *task
);
Gets the GMainContext that task
will return its result in (that
is, the context that was the
thread-default main context
at the point when task
was created).
This will always return a non-NULL
value, even if the task's
context is the default GMainContext.
Since 2.36
gpointer
g_task_get_source_object (GTask *task
);
Gets the source object from task
. Like
g_async_result_get_source_object()
, but does not ref the object.
Since 2.36
gpointer
g_task_get_source_tag (GTask *task
);
Gets task
's source tag. See g_task_set_source_tag()
.
Since 2.36
void g_task_return_boolean (GTask *task
,gboolean result
);
Sets task
's result to result
and completes the task (see
g_task_return_pointer()
for more discussion of exactly what this
means).
Since 2.36
void g_task_return_int (GTask *task
,gssize result
);
Sets task
's result to result
and completes the task (see
g_task_return_pointer()
for more discussion of exactly what this
means).
Since 2.36
void g_task_return_pointer (GTask *task
,gpointer result
,GDestroyNotify result_destroy
);
Sets task
's result to result
and completes the task. If result
is not NULL
, then result_destroy
will be used to free result
if
the caller does not take ownership of it with
g_task_propagate_pointer()
.
"Completes the task" means that for an ordinary asynchronous task
it will either invoke the task's callback, or else queue that
callback to be invoked in the proper GMainContext, or in the next
iteration of the current GMainContext. For a task run via
g_task_run_in_thread()
or g_task_run_in_thread_sync()
, calling this
method will save result
to be returned to the caller later, but
the task will not actually be completed until the GTaskThreadFunc
exits.
Note that since the task may be completed before returning from
g_task_return_pointer()
, you cannot assume that result
is still
valid after calling this, unless you are still holding another
reference on it.
task |
a GTask |
|
result |
the pointer result of a task function. |
[allow-none][transfer full] |
result_destroy |
a GDestroyNotify function. |
[allow-none] |
Since 2.36
void g_task_return_error (GTask *task
,GError *error
);
Sets task
's result to error
(which task
assumes ownership of)
and completes the task (see g_task_return_pointer()
for more
discussion of exactly what this means).
Note that since the task takes ownership of error
, and since the
task may be completed before returning from g_task_return_error()
,
you cannot assume that error
is still valid after calling this.
Call g_error_copy()
on the error if you need to keep a local copy
as well.
See also g_task_return_new_error()
.
Since 2.36
void g_task_return_new_error (GTask *task
,GQuark domain
,gint code
,const char *format
,...
);
Sets task
's result to a new GError created from domain
, code
,
format
, and the remaining arguments, and completes the task (see
g_task_return_pointer()
for more discussion of exactly what this
means).
See also g_task_return_error()
.
Since 2.36
gboolean
g_task_return_error_if_cancelled (GTask *task
);
Checks if task
's GCancellable has been cancelled, and if so, sets
task
's error accordingly and completes the task (see
g_task_return_pointer()
for more discussion of exactly what this
means).
Since 2.36
gboolean g_task_propagate_boolean (GTask *task
,GError **error
);
Gets the result of task
as a gboolean.
If the task resulted in an error, or was cancelled, then this will
instead return FALSE
and set error
.
Since this method transfers ownership of the return value (or error) to the caller, you may only call it once.
Since 2.36
gssize g_task_propagate_int (GTask *task
,GError **error
);
Gets the result of task
as an integer (gssize).
If the task resulted in an error, or was cancelled, then this will
instead return -1 and set error
.
Since this method transfers ownership of the return value (or error) to the caller, you may only call it once.
Since 2.36
gpointer g_task_propagate_pointer (GTask *task
,GError **error
);
Gets the result of task
as a pointer, and transfers ownership
of that value to the caller.
If the task resulted in an error, or was cancelled, then this will
instead return NULL
and set error
.
Since this method transfers ownership of the return value (or error) to the caller, you may only call it once.
Since 2.36
gboolean
g_task_had_error (GTask *task
);
Tests if task
resulted in an error.
Since 2.36
void g_task_run_in_thread (GTask *task
,GTaskThreadFunc task_func
);
Runs task_func
in another thread. When task_func
returns, task
's
GAsyncReadyCallback will be invoked in task
's GMainContext.
This takes a ref on task
until the task completes.
See GTaskThreadFunc for more details about how task_func
is handled.
Since 2.36
void g_task_run_in_thread_sync (GTask *task
,GTaskThreadFunc task_func
);
Runs task_func
in another thread, and waits for it to return or be
cancelled. You can use g_task_propagate_pointer()
, etc, afterward
to get the result of task_func
.
See GTaskThreadFunc for more details about how task_func
is handled.
Normally this is used with tasks created with a NULL
callback
, but note that even if the task does
have a callback, it will not be invoked when task_func
returns.
Since 2.36
void (*GTaskThreadFunc) (GTask *task
,gpointer source_object
,gpointer task_data
,GCancellable *cancellable
);
The prototype for a task function to be run in a thread via
g_task_run_in_thread()
or g_task_run_in_thread_sync()
.
If the return-on-cancel flag is set on task
, and cancellable
gets
cancelled, then the GTask will be completed immediately (as though
g_task_return_error_if_cancelled()
had been called), without
waiting for the task function to complete. However, the task
function will continue running in its thread in the background. The
function therefore needs to be careful about how it uses
externally-visible state in this case. See
g_task_set_return_on_cancel()
for more details.
Other than in that case, task
will be completed when the
GTaskThreadFunc returns, not when it calls a
g_task_return_
function.
task |
the GTask |
|
source_object |
|
[type GObject] |
task_data |
|
|
cancellable |
|
Since 2.36
void g_task_attach_source (GTask *task
,GSource *source
,GSourceFunc callback
);
A utility function for dealing with async operations where you need
to wait for a GSource to trigger. Attaches source
to task
's
GMainContext with task
's priority, and sets source
's
callback to callback
, with task
as the callback's user_data
.
This takes a reference on task
until source
is destroyed.
task |
a GTask |
|
source |
the source to attach |
|
callback |
the callback to invoke when |
Since 2.36
gboolean g_task_is_valid (gpointer result
,gpointer source_object
);
Checks that result
is a GTask, and that source_object
is its
source object (or that source_object
is NULL
and result
has no
source object). This can be used in g_return_if_fail()
checks.
result |
A GAsyncResult. |
[type Gio.AsyncResult] |
source_object |
the source object expected to be associated with the task. |
[allow-none][type GObject] |
Since 2.36


Oops, you need to build the package before running this example. It's easy: just run rake
in the project's directory.
This examples shows how to add custom buttons and actions with the built-in toolbar class.
Event.observe(window, 'load', function() {
var editor = WysiHat.Editor.attach('content');
var toolbar = new WysiHat.Toolbar(editor);
// The name will be used for the div class and the command to execute
// The label is the text you see for the button.
toolbar.addButton({ name: 'bold', label: "Strong" });
// The label is the only required option. If no name is given,
// the label will be downcased and set to the name.
toolbar.addButton({ label: "Underline" });
// You can override all the conventions by passing in your own
// name, label, handler, and query options.
toolbar.addButton({
name: 'em',
label: "Emphasis",
handler: function(editor) { editor.italicSelection(); },
query: function(editor) { return editor.italicSelected(); }
});
});


--- layout: page title: Projects permalink: /projects/ ---
Created an informational website using basic HTML and CSS for a fictitious chess club. Mr. Chuck Wahle graded this as a final project for his Website Construction course in the spring of 2013.
Check out the Chess Enthusiast homepage.
I also created a repository for this project on my GitHub Account.


Please use the form below to create an exam.
Exam type {{exam.type | examType}} will be conducted in {{exam.campus}}'s for {{exam.course.title}} {{exam.class | classType}}.
Exam type {{exam.type | examType}} will be conducted in {{exam.campus}}'s for {{exam.course.title}} {{exam.class | classType}}.


Ayahuasca (M. hostilis & Syrian Rue)
For two first-timers (190 lbs and 120 lbs)
Preparation
===========
6 g Syrian Rue
14 g Mimosa Hostilis
1000 cc Ascorbic Acid (Vitamin C)
6 tbsp Lemon Juice
Filtered Water (approx half gallon)
I crushed the Rue by hand with a mortar and pestle until it was almost a powder. This took at least half an hour of pretty hard work (I got a good-sized blister on my hand), so if you have a coffee grinder, you might want to try that instead. Then I shredded up the Mimosa into one inch long strips, about 1/4' wide each. Don't try to crush those by hand, you won't be able to and you don't need to.
I prepared two solutions of filtered water, somewhere between a pint and a quart each, and added one 500 cc V-C tablet and two tbsps of lemon juice to each.
I tossed one of the water solutions, and all the Rue and Mimosa, into a metal saucepan and heated until it was a low boil. Stir it often. Don't let the concoction go dry - add water as needed. I kept about an inch deep of brew. After 20 minutes, strain the brew through a metal meshed tea strainer into another container. Press down on the mush to get all the liquid out. Set container aside.
Put the mush back into the saucepan and add the second water solution. Repeat process (I cheated a bit and went a bit short of 20 minutes) and empty into container.
Repeat process a third time, except this time I used straight filtered water with 2 tbsp of lemon juice (no V-C this time). At this last stage, I took a potato masher and smooshed up the Rue and Mimosa in the bottom of the saucepan, to make sure I got full mileage out of the concoction. Then empty into container. You are done now with the mush and can discard it.
Take the solution that's in the container and if needed, you can simmer that for a while to reduce the amount of liquid. I started to do that, but there was only about two cups total in there anyway so I skipped this last step. I poured the solution into two coffee cups, giving myself about 55% and my wife 45%. In retrospect, given our weight difference, I probably should've got more like 60/40. But perhaps it wouldn't have mattered all that much. Let stand for a few minutes to cool down if you like.
Experience
==============
(Note: I have had some experience with Psylocibin and LSD, but it was over 20 years ago)
I knew how awful the stuff was going to taste so I literally held my nose and gulped down the brew in about 4 swallows over the space of a minute.  I think this helped me tremendously. It prevented any automatic gag reflex which would've wasted the entire thing. My wife used a difference tact and sipped hers slowly over about 20 minutes, nostrils fully open. She seemed to want to experience it more fully, bad taste and all. She's more brave than I am.
A side note - my wife hadn't eaten anything for 12 hours prior; I had eated about 6 hours prior, McDonalds no less. I am ashamed. Not really.
After about 20 minutes, I started to feel a little loopy, but it was more like being slightly stoned then anything else. I suppose this was the Rue kicking in, but it's hard to tell since both ingredients were cooked together. Pleasant, relaxing, a little tingly, but not much else. After about 40 minutes I began to wonder if I had not made enough. I deliberately used less Mimosa than was recommended by almost every experienced tripper because I knew how potent DMT was, and I wanted to err on the side of caution. I would've preferred no trip at all to an insane and dangerous one. At least I had experience now in cooking the brew!
My wife decided to go lie down due to her constant nausea. I had a little bit of stomach upset, but it seemed very much in control. I drank a glass of water at this point. This may also have helped out in the overall process. After that, my nausea went away completely. 100%. Whatever was going to happen, my stomach would have no part in it. I joined my wife in the bedroom and laid down.
It was at this point that IT KICKED IN. Oh, my god. I was trying to say something to my wife, and my thought process just stopped.  Curiously, my wife asked me right then if I was seeing crazy spinning colors, so I knew she was going into a similar place at the same time. From there, it quickly grew into a hard driving, frantic, spirographic, nightmarish exctasy that was to last for the next 3 hours.
The best way I can describe it is have you look at the inside cover for Guns & Roses Appetite for Descruction album. The picture of the demon jumping over the fence to slay the rapist robot. Those are the imps that ran the film projector for the event. Totally bizarre and sometimes frightening images dancing madly across the ceiling and in my head. Could these be the maninkari, the spirits the ayahusaqueros talk about? Probably not. If anything these were simple puppets controlled by forces unseen by this entry-level tripper. Fortunately, I never felt threatened by them. They were just there to entertain, and not dominate - I'm assuming because of the low dosage we took.
The colors were astonishing. I can't describe the vibrancy. Spinning wheels of flourescence and dancing gemoetric patterns were constant throughout the entire experience. Thousands of vacant eyes popping out of the walls. Mouths opening up on the ceiling as it breathed. Brilliant lights shining through any crack, real or perceived.
By the way, it was almost impossible to talk. I tried to describe my experiences to my wife, and she to me, but neither of us could get very far before we had to drift off to stare with dropped jaw to yet more craziness. I babbled like a toddler for a while.
As it became more frenzied, the gremlins became more bold. Smiles turned into grimaces. Laughter turned into teeth gnashing. I had the opportunity to go deeper. I was asked by Them if I wanted to go deeper. I considered it, but decided against it.
I needed to maintain a hold on reality. For one, my wife was having a difficult experience and I needed to keep my head around that. Two, I am not young anymore and I didn't want some dumbassed cardiac failure. And three, this experience was so new, so novel, that I didn't know where it might end up. I guess I'm a cautious tripper if that isn't an oxymoron. So, I got up and left the bedroom and fed the cats. I put a couple of dishes away and then returned to bed. It was difficult to walk, but I was able to see just fine. My cats didn't become dogs, and my dishes didn't run away with the spoons. It felt good to know I had self-control for the experience. Perhaps at some later attempt I'll truly let go, but it's better to have this grounding at first, in my opinion.
From then on it was just pure enjoyment of the show. It lasted a couple more hours before I was finally able to drift off to sleep. It's funny that the images became more mundane as the brew wore off, but no less visual. 1960s metal lunch boxes and classic highway billboard advertisements were buzzing around for the next 45 minutes. The colors became more subdued, yellows, light blues, light greens. Much different from the insane color explosions earlier. Very pleasant but also somewhat painfully nostalgic. Weird.
At this point I became very introspective. I unpeeled myself to see if I could see anyone in there. It was frightening at first because I didn't find any core, only the onion peels. Was I just a shell of a man? Well, maybe. But then I realized that my life was a series of experiences and that it's the experience that makes the man (so they say), so I didn't despair too much. I did realize how self-centered I've been all my life, and I vowed to the gods and to my wife to change that.
My wife, unfortunately, had a less thrilling experience. Although she saw wonderful, awe-inspiring things, it was tempered by her constant nausea. Finally, after about three hours into it, she finally was able to purge it all out and was at least able to drift off into colorful sleep.
I stayed awake for another hour or so, letting the experiencing slowly seep away. One thing I was grateful for was how little of a hangover there was (none). Just less and less intensity until I was back to full reality. Very nice. I woke up the next morning still kind of high (gentle buzzing) and I pleasantly sobered up throughout the day.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.