Saxon allows you to write your own URIResolver
to handle the URIs of input documents, as
defined in the JAXP 1.2 specification. Such a URIResolver
is used to process the URIs supplied to the
doc()
and document()
functions. It is also used to process the URIs supplied for the
source document and the stylesheet on the command line. In XSLT it is used to process the URIs used
in the xsl:include
and xsl:import
and xsl:import-schema
declarations,
and in XQuery it supports the location URIs in import module
and import schema
.
The URIResolver
is called to process
the supplied URI, and it returns a JAXP Source
object, which Saxon uses as the source of
the input. Note that the Source
must be one of the implementations of Source
that Saxon
recognizes: you cannot write your own implementations of the JAXP Source
class.


oggz.h File Reference
The liboggz C API.
More...
#include <stdio.h>
#include <sys/types.h>
#include <ogg/ogg.h>
#include <oggz/oggz_constants.h>
#include <oggz/oggz_table.h>
#include <oggz/oggz_off_t.h>
#include <oggz/oggz_read.h>
#include <oggz/oggz_stream.h>
#include <oggz/oggz_seek.h>
#include <oggz/oggz_write.h>
#include <oggz/oggz_io.h>
#include <oggz/oggz_comments.h>
#include <oggz/oggz_deprecated.h>
Go to the source code of this file.
Typedefs |
| typedef void | OGGZ |
| | An opaque handle to an Ogg file.
|
Functions |
| OGGZ * | oggz_new (int flags) |
| | Create a new OGGZ object.
|
| OGGZ * | oggz_open (const char *filename, int flags) |
| | Open an Ogg file, creating an OGGZ handle for it.
|
| OGGZ * | oggz_open_stdio (FILE *file, int flags) |
| | Create an OGGZ handle associated with a stdio stream.
|
| int | oggz_flush (OGGZ *oggz) |
| | Ensure any associated io streams are flushed.
|
| long | oggz_run (OGGZ *oggz) |
| | Run an OGGZ until completion, or error.
|
| int | oggz_run_set_blocksize (OGGZ *oggz, long blocksize) |
| | Set the blocksize to use internally for oggz_run().
|
| int | oggz_close (OGGZ *oggz) |
| | Close an OGGZ handle.
|
| int | oggz_get_bos (OGGZ *oggz, long serialno) |
| | Determine if a given logical bitstream is at bos (beginning of stream).
|
| int | oggz_get_eos (OGGZ *oggz, long serialno) |
| | Determine if a given logical bitstream is at eos (end of stream).
|
| int | oggz_get_numtracks (OGGZ *oggz) |
| | Query the number of tracks (logical bitstreams).
|
| long | oggz_serialno_new (OGGZ *oggz) |
| | Request a new serialno, as required for a new stream, ensuring the serialno is not yet used for any other streams managed by this OGGZ.
|
| const char * | oggz_content_type (OggzStreamContent content) |
| | Return human-readable string representation of a content type.
|
Detailed Description
The liboggz C API.
All access is managed via an OGGZ handle. This can be instantiated in one of three ways:
To finish using an OGGZ handle, it should be closed with oggz_close().
To read from Ogg files or streams you must instantiate an OGGZ handle with flags set to OGGZ_READ, and provide an OggzReadPacket callback with oggz_set_read_callback(). See the Oggz Read API section for details.
To write to Ogg files or streams you must instantiate an OGGZ handle with flags set to OGGZ_WRITE, and provide an OggzWritePacket callback with oggz_set_write_callback(). See the Oggz Write API section for details.
To seek while reading Ogg files or streams you must instantiate an OGGZ handle for reading, and ensure that an OggzMetric function is defined to translate packet positions into units such as time. See the Oggz Seek API section for details.
When an OGGZ handle is instantiated by oggz_open() or oggz_open_stdio(), Oggz uses stdio functions internally to access the raw data. However for some applications, the raw data cannot be accessed via stdio -- this commonly occurs when integrating with media frameworks. For such applications, you can provide Oggz with custom IO methods that it should use to access the raw data. Oggz will then use these custom methods, rather than using stdio methods, to access the raw data internally.
For details, see <oggz/oggz_io.h> .
oggz.h provides direct access to libogg types such as ogg_packet, defined in <ogg/ogg.h>.
Typedef Documentation
An opaque handle to an Ogg file.
This is returned by oggz_open() or oggz_new(), and is passed to all other oggz_* functions.
Function Documentation
| int oggz_close |
( |
OGGZ * |
oggz |
) |
|
Close an OGGZ handle.
- Parameters:
-
- Return values:
-
| 0 | Success |
| OGGZ_ERR_BAD_OGGZ | oggz does not refer to an existing OGGZ |
| OGGZ_ERR_SYSTEM | System error; check errno for details |
Return human-readable string representation of a content type.
- Return values:
-
| string | the name of the content type |
| NULL | content invalid |
| int oggz_flush |
( |
OGGZ * |
oggz |
) |
|
Ensure any associated io streams are flushed.
- Parameters:
-
- Return values:
-
| 0 | Success |
| OGGZ_ERR_BAD_OGGZ | oggz does not refer to an existing OGGZ |
| OGGZ_ERR_INVALID | Operation not suitable for this OGGZ |
| OGGZ_ERR_SYSTEM | System error; check errno for details |
| int oggz_get_bos |
( |
OGGZ * |
oggz, |
|
|
long |
serialno | |
|
) |
| | |
Determine if a given logical bitstream is at bos (beginning of stream).
- Parameters:
-
| oggz | An OGGZ handle |
| serialno | Identify a logical bitstream within oggz, or -1 to query if all logical bitstreams in oggz are at bos |
- Return values:
-
| 1 | The given stream is at bos |
| 0 | The given stream is not at bos |
| OGGZ_ERR_BAD_SERIALNO | serialno does not identify an existing logical bitstream in oggz. |
| int oggz_get_eos |
( |
OGGZ * |
oggz, |
|
|
long |
serialno | |
|
) |
| | |
Determine if a given logical bitstream is at eos (end of stream).
- Parameters:
-
| oggz | An OGGZ handle |
| serialno | Identify a logical bitstream within oggz, or -1 to query if all logical bitstreams in oggz are at eos |
- Return values:
-
| 1 | The given stream is at eos |
| 0 | The given stream is not at eos |
| OGGZ_ERR_BAD_SERIALNO | serialno does not identify an existing logical bitstream in oggz. |
| int oggz_get_numtracks |
( |
OGGZ * |
oggz |
) |
|
Query the number of tracks (logical bitstreams).
When reading, this number is incremented every time a new track is found, so the returned value is only correct once the OGGZ is no longer at bos (beginning of stream): see oggz_get_bos() for determining this.
- Parameters:
-
- Returns:
- The number of tracks in OGGZ
- Return values:
-
| OGGZ_ERR_BAD_SERIALNO | serialno does not identify an existing logical bitstream in oggz. |
| OGGZ* oggz_new |
( |
int |
flags |
) |
|
Create a new OGGZ object.
- Parameters:
-
| flags | OGGZ_READ or OGGZ_WRITE |
- Returns:
- A new OGGZ object
- Return values:
-
| NULL | on system error; check errno for details |
| OGGZ* oggz_open |
( |
const char * |
filename, |
|
|
int |
flags | |
|
) |
| | |
Open an Ogg file, creating an OGGZ handle for it.
- Parameters:
-
| filename | The file to open |
| flags | OGGZ_READ or OGGZ_WRITE |
- Returns:
- A new OGGZ handle
- Return values:
-
| NULL | System error; check errno for details |
| OGGZ* oggz_open_stdio |
( |
FILE * |
file, |
|
|
int |
flags | |
|
) |
| | |
Create an OGGZ handle associated with a stdio stream.
- Parameters:
-
| file | An open FILE handle |
| flags | OGGZ_READ or OGGZ_WRITE |
- Returns:
- A new OGGZ handle
- Return values:
-
| NULL | System error; check errno for details |
| long oggz_run |
( |
OGGZ * |
oggz |
) |
|
Run an OGGZ until completion, or error.
This is a convenience function which repeatedly calls oggz_read() or oggz_write() as appropriate. For an OGGZ opened for reading, an OggzReadPacket or OggzReadPage callback should have been set before calling this function. For an OGGZ opened for writing, either an OggzHungry callback should have been set before calling this function, or you can use this function to write out all unwritten Ogg pages which are pending.
- Parameters:
-
| oggz | An OGGZ handle previously opened for either reading or writing |
- Return values:
-
| 0 | Success |
| OGGZ_ERR_BAD_OGGZ | oggz does not refer to an existing OGGZ |
| OGGZ_ERR_INVALID | Operation not suitable for this OGGZ |
| OGGZ_ERR_SYSTEM | System error; check errno for details |
| OGGZ_ERR_STOP_OK | Operation was stopped by a user callback returning OGGZ_STOP_OK |
| OGGZ_ERR_STOP_ERR | Operation was stopped by a user callback returning OGGZ_STOP_ERR |
| OGGZ_ERR_RECURSIVE_WRITE | Attempt to initiate writing from within an OggzHungry callback |
| int oggz_run_set_blocksize |
( |
OGGZ * |
oggz, |
|
|
long |
blocksize | |
|
) |
| | |
Set the blocksize to use internally for oggz_run().
- Parameters:
-
| oggz | An OGGZ handle previously opened for either reading or writing |
| blocksize | The blocksize to use within oggz_run() |
- Return values:
-
| 0 | Success |
| OGGZ_ERR_BAD_OGGZ | oggz does not refer to an existing OGGZ |
| OGGZ_ERR_INVALID | Invalid blocksize (run_blocksize <= 0) |
| long oggz_serialno_new |
( |
OGGZ * |
oggz |
) |
|
Request a new serialno, as required for a new stream, ensuring the serialno is not yet used for any other streams managed by this OGGZ.
- Parameters:
-
- Returns:
- A new serialno, not already occuring in any logical bitstreams in oggz.


Sweden drops probe in Julian Assange ‘rape’ case
The WikiLeaks founder has been in custody in the UK since his removal from Ecuador’s embassy in London.
The alleged rape investigation involving WikiLeaks founder Julian Assange, who is now jailed in Britain, has been discontinued, a Swedish prosecutor has said.
Deputy Chief Prosecutor Eva-Marie Persson spoke on Tuesday as she gave an update on the Swedish case.
Assange has been in custody since being removed from the Ecuadorian embassy in London where he had initially been granted asylum.
He had been wanted in Sweden over the rape claims but is also sought by US authorities over his WikiLeaks activities.


B.P 25 Sarue de Bruno Dantokpa cotonou Republiqe du Benin Dear sir, I got your contact while searching for somebody who will be of immediate assistance to me , then I decided to forward this business proposal to you with hope that it will be of benefit to both of us. I'm Frank Guei Jnr, the first Son of late Gen. Robert Guei the former military ruler of ( cote d' Ivoire/ivory coast,) who was killed on 19/9/2002 with some of his loyalist officers during a cross fire battle between them and government troops in his attempt to seize power through coup de eta in Abidjan on 19/9/2002 . In brief, I have the sum of Twenty Million Seven Hundred Thousand united states dollars(us$20,700,000)only which I want to move out of here with most desperation. This money was deposited by my late father in a security company for the purpose of using it to fine tune his administration in the invent that he succeed in the fail coup attempt. While I was also made the sole beneficiary and next of kin as the first son of my father. So because of the present situation in my country cote d' ivoire , my mother advised me before she was mudered cold bloodedly with 18 of my sibblings to leave the country immediately for security reasons, and also to look for a trust worthy foreign partner who can assist me to transfer the money out of Cotonou-Benin Republic to his private or company's account for investment as the security company had earlier rejected my application for the withdrawal of the money because I am underaged. Sir, I highly need your unreserved assistance both in transferring the money to your country and also investing it in a profitable venture with your kind advice,as I confide in you hoping you will never betray me at last.My guidian and myself have proposed (20%) percent of the total sum of the money for you as your own commission,and (5%) for any expensis that you might incure in the process so that you can give us all necessary assistance and protection we may need in our investment in your Country. Please treat as highly confidential because our future depends on this money. All the vital documents covering the deposit of this fund in a security company are with me here in Cotonou, and will be used to effect change of ownership in your favour for subsequent transfer to any account you may wish us to use abroad. The identity of the finance company where the fund is deposited will be revealed to you as soon as I recieve confirmation from you on your willingness to proceed.Even our family lawyer thatassisted my father when he was depositing the money has been approched on this issue and he promised to give us all the legal backing that might be required in this transfer. Reach me through this mail box to discuss modalities on how to proceed. Looking forward to hearing from you urgently. Best wishes. Frank Guei Jnr.


Pynamixel¶
Pynamixel is a Python (2.7+ and 3.4+) library to use Robotis Dynamixel servos. It supports several hardwares (see below) and adding a new one is easy. It provides different layers allowing very precise control as well as a greater abstraction.
It’s licensed under the MIT license. It’s available on the Python package index, its documentation and its source code are on GitHub.
Questions? Remarks? Bugs? Want to contribute? Open an issue!
Supported hardwares¶
“Full support” means on Windows, Linux and Mac OS X, with both Python 2.7+ and 3.4+.
- USB2AX: full support
- USB2Dynamixel: not yet
- U2D2: not yet
Quick start¶
Install from PyPI:
$ pip install Pynamixel
Import:
>>> import Pynamixel
Create a hardware:
>>> hardware = Pynamixel.hardwares.USB2AX("/dev/ttyACM0", 1000000)
Create a system and a device:
>>> system = Pynamixel.System(Pynamixel.Bus(hardware))
>>> servo = system.add_device(Pynamixel.devices.AX12, 1)
Set the servo’s goal position:
>>> servo.goal_position.write(0x200)
And see that it’s moving:
>>> servo.moving.read()
1


My last Blackberry
I consider myself an early mobile adopter. I had Casio PDA, Sharp PDA (the first to sync with the PC), a Psyon, the original Palm, a Nokia communicator. Finannyl I ended with a Blackberry 8707. It did eMail very well, the big keys matched my big hands and live was good. Of course even I fall victim to perceived obsolence. The 8707 showed its age. All the new applications like Quickr, Facebook, Tripit etc. wouldn't run and first and foremost: no wifi and no option to keep the phone running while roaming but switch the data off. So I decided to treat myself to a shiny new Bold2 9700 (mostly since Android hasn't been cleared by IBM security yet, at least not here).
It had all I wished for: applications, camera, memory, wifi, roaming. Others praised it as their parachute. Seems mine has a few burn holes and it will be my last Blackberry unless things improve dramatically very soon.
It had all I wished for: applications, camera, memory, wifi, roaming. Others praised it as their parachute. Seems mine has a few burn holes and it will be my last Blackberry unless things improve dramatically very soon.
- BES jail: I paid for the unit. I foot the monthly bill (and to connect to a Enterprise Server Singapore's mobile provider require the premium plan). Nevertheless I'm not in charge. The configuration settings are hidden in what Blackberry calls "Service books" which only can be issued by the BES admininstrator. Lets say he is trying very hard.
- Browser confusion: there is the Blackberry browser, the hotspot browser and the Gee browser (the later courtesy of Starhub). Depending on connectivity one or the other works or doesn't work.  The 8707 at least didn't try and resulted in ugly but readable pages. The new browsers try hard and render unreadable small pages. There are only 3 zoom levels and the browser forgets them graciously between pages
- Network reliability: I don't want to care if I'm in a hotspot or mobile ot inside my firewall. Once I teach a device how things are it should work behind the scenes. The 9700 doesn't. Messages are not sent without explanation. It only tries for a few seconds - sometimes, sometimes it sends and receives within the blink of an eye. Services are not network flexible. Some work on mobile but not wifi (e.g. the Blackberry marketplace), some on wifi but not mobile, some only if only one is on. Behaving like this I don't consider it a trusted device anymore.
- Keyboard: The 8707 is superior to the 9700, so I expect a further detoriation
- Buggy software:Incoming and outgoing calls are associated with random numbers. E.g. notification I get from TripIt (a UK SMS) is linked to my aunties German handphone number. I called a cab, the log later says: "Call to cab" but listing my wife's number as destination
- Desktop software: I use Linux as my day to day OS. For a lot of functions I need a BB desktop client. It is mainly Windows, so I need to keep either a VM with working USB or a separate machine around
- Not my problem: The phone company tells me it is a BES issue, the BES admin blames the phone company, nobody I can visit and sort things out and the hardware guys (maybe my unit is faulty?) don't understand a thing about networks.
Posted by Stephan H Wissel on 30 March 2010 | Comments (5) | categories: Technology


This simple page demonstrates how to use infuse.host without webpack.
When the page is loaded, the <template> element is parsed, cloned, and infused. The resulting fragment (
Page Title
) is added to the  element.
<template>

Page Title


title = "Home Page" url = "/" layout = "default" is_hidden = 0 [JustinDoyle\Carousel\Components\Carousel carousel] selected_carousel = 3 [editable] file = "awards/column_middle.htm" ==


C Costello
vs
M Fogg
"Bishop and Costello"
(game of the day 2019-09-24)
Tradewise Gibraltar (2011.01.28), Catalan Bay GIB
Queen's Gambit Declined, Tarrasch(D34)
·
1-0
«
<
>
»
+
ANALYSIS
[
x
]
Light
Squares
Dark
Squares
Flip
Board
Labels
ON
Shrink
Grow
Copy
SETTINGS
ENGINE
FEN COPIED


3
1 And now, brothers, pray for us, that the word of the Lord may spread rapidly and be glorified, even as it also is with you,
2 and that we may be delivered from wicked and evil people, for not all have faith.
3 But the Lord is faithful, who will establish you and guard you from the evil one.
4 We have confidence in the Lord concerning you, that you both do and will continue to do the things that we command.
5 May the Lord direct your hearts to the love of God and to the endurance of Christ.
6 Now we command you, brothers, in the name of our Lord Jesus Christ, that you avoid every brother who lives idly and not according to the traditions that you received from us.
7 For you know yourselves how you ought to imitate us.  Instead, we worked night and day in difficult labor and hardship, so we might not be a burden to any of you.
9 It is not that we do not have authority, but that we should be an example to you, so that you may imitate us.
10 When we were with you we commanded you, "If any one does not want to work, he should not eat."
11 For we hear that some walk idly among you; they do not work but are instead meddlers.
12 Now such ones we command and exhort in the Lord Jesus Christ, that with quietness they should work and eat their own food.
13 But you, brothers, do not lose heart in doing what is right.
14 If anyone does not obey our word in this letter, take note of him and have no association with him, so that he may be ashamed.
15 Do not consider him as an enemy, but warn him as a brother.
16 May the Lord of peace himself give you peace at all times in all ways. The Lord be with you all.
17 This is my greeting, Paul, with my own hand, which is the sign in every letter I write.
18 May the grace of our Lord Jesus Christ be with you all.


{# Copyright (c) 2014 Kevin Bell. All rights reserved. #} {# See the file LICENSE.txt for copying permission. #} {% extends "base.html" %} {% load static %} {% block content %}


|
WelcomeWelcome to Emerald. You are about to enter a world of fantastical wonders in a world never-before-seen to the naked eye. GameplayControlsWhen playing or playtesting a level, the player must control their character by using the arrow keys on the bottom right of your keyboard. You also have the option of using other keys: W = up, A = left, D = right. The character will jump when an upwards-implied key is pressed. The character will move to the right when a rightwards-implied key is held and vice-versa with a leftwards-implied key is held. MissionYour goal is to reach the Goalpost of your level. In every level, there is a Goalpost depicted in the style of ASCII art.
PasswordsIn the campaign, you may need to leave the site or take a break after a while. A password system has been implemented so you can continue from the state they've left off from. The password is in the form of a 3x3 ASCII art illustration and is only shown after beating a level in the campaign. In order to secure your progress, it is suggested that you write it down or save it on a digital stickynote by creating an account with another EthanThatOneKid webapp called Stickes. MakerThere exists a subsection within Emerald called Maker. There are various tools for making ASCII-styled platformer levels from scratch in the maker. These tools will be further elaborated on below. Model CreatorIn the Maker subsection of Emerald, there dwells a curious box on the left side of the tools section. This is the Model Creator. The Model Creator allows the user to create custom models for their levels. Two scrollable inputs control the dimensions of your model. For practice, you can make a piece of ground for your character to stand on. First, go to the Model Creator in your blank level. Second, decrease the vertical scrollbar until there is one row. Third, fill that row with characters from your keyboard; preferebly one that resembles a solid object such as #. Finally, title your new model ground and then click add to list. Now, it is a usable model just like the others in your tools. To edit an existing model, select it by clicking its title and make your changes in the model creator. This time when you click add to list, it will ask you if you would like to save over it. Agree, and you will have successfully edited your custom model. Maker ToolsIf you wish to place a model into the game's world, select it by clicking its title and then click on a cell in the screen that you would like to place the model within. If you do not like the position that you have placed your model, you have to ability to undo your previous moves by clicking UNDO on the right side of the page in the green box. AuthenticationYou may have noticed some required text fields in the maker that display various annoying error messages. This is to ensure that each player gets premium security on each level created. When you create a new level, it must have a unique title, unlike any other levels created prior. Also, a key(or password) must be created for that specific level in order to ensure that only you(or anyone who you choose to share your key with) has the ability to edit the level. It is suggested that you write it down or save it on a digital stickynote by creating an account with another EthanThatOneKid webapp called Stickes. It may also be in your interest to give your screen name in the field entitled Creator of this Level so that people can search for your levels by screen name in the User-Created Levels subsection of Emerald and also so you can get some recognition for creating cool levels. The ASCII StyleWhat is ASCII Art?ASCII is an acronym standing for American Standard Code for Information Interchange. It is commonly pronounced as ASS-KEE. Why ASCII Art?[DEVELOPER TRANSMISSION] I chose to use ASCII art in a game like this because my first programming language was BASIC. In that language, I created countless programs with various ASCII art images. I had always been curious, only having made static images with ASCII art, how it would look for it to move in response to a player's action. The idea had always been in the back of my mind and with my knowledge about using the web to produce games I finally decided to go full-scale on this type of project. Devotions[DEVELOPER TRANSMISSION] I devote this project and all of my effort to all of my friends and family. References |


{% extends "layout.html" %} {% block title %} Members {% endblock %} {% block main %} This is the Members only page. You are logged in... SHHHHHHHH! {% endblock %}


Bounding box
Title
Date
Filter by map extent
{{composition.title}}
delete
share
info
chevron_left
Previous composition list
Composition {{compStart + 1}} - {{compNext}}
Composition {{compStart + 1}} - {{data.compositionsCount}}
chevron_right
Next composition page


Debug:
Auto Replace:
Show all:
Host:
Status
Clear All Data
Filter:
Add this to the hosts file:
#Siderite's DNS Resolver


Buhari sympathizes with Kenya, DRC over fatal floods, mudslides
by Salome NuhuPresident Muhammadu Buhari on Sunday expressed his compassion with the government and people of Kenya and Democratic Republic of Congo, DRC, over the fatal floods and devastating mudslides that wreaked havoc in certain parts of their countries.
Addressing the recent incidents in both countries, Mr Buhari said “the government of Nigeria sympathizes with you and the victims of these deadly and devastating flood disasters and mudslides.”
He said it is important for Africa to develop an emergency management response system that will drastically reduce the impact of such occurrences.
“Emergency management response is one of Africa’s biggest challenges of development, and we should work together to find a common strategy to minimize the human and economic impacts of these catastrophes,” he said.
Kenya
PREMIUM TIMES reported how at least 24 people were killed by landslides and floods in West Pokot County, Kenya on Saturday.
The landslides and floods are said to have been caused by torrential rains.
The coordinator of Kenya’s National Government Affirmative Action Fund, Emmanuel Ameme, revealed that “an undisclosed number of people were missing on Saturday, while infrastructure including roads and bridges had been damaged.”
Damages in Kenya are expected to be worse because the rivers are swelling again.
Democratic Republic of Congo
The Guardian Newspaper also reported on Saturday that 25 people had been killed in the DRC’s northwestern Equateur.
Ten deaths were recorded in DRC province of North Ubangi, more than 180,000 people need humanitarian support and at least 50,000 people were affected by the continuous downpour.
These devastating figures have led the government to declare a state of emergency.


Audio scheduler virtual machine
A tutorial by Graham Wakefield & Charlie Roberts published originally here.
We have designed a target language that captures some essential concepts for a musical live coding context, such as playing notes and looping patterns. It is intentionally limited to make it fairly easy to learn, yet also intentionally designed to make it possible to express a wide variety of ideas. It is not designed to be succinct -- that's the job of the user-facing language you create! The target language is a bit like the instruction sequences real compilers use, in that it is a list of commands. However ours can also have nested structures as lists of lists. A simple example is a pattern that plays a note every beat:
["@loop", ["@pluck", [1, "@wait"]]]
Sounds
The VM comes with a small number of instruments to get things going. Here's a plucked string instrument. There are two ways to trigger it. You can use @pluck-note to set the frequency and amplitude for each note like this:
[440, 1, "@pluck-note"]
[880, 0.25, "@pluck-note"]
Or you can set the frequency and amplitude as contextual variables, and just use @pluck to trigger using these values. This can allow a bit more flexibility in how these values are calculated:
["@pluck"]
[[330, "freq", "@set"], [0.5, "amp", "@set"], "@pluck"]
There are also some percussion sounds, which either grab amplitude from the context (set using @set-amp), or specify it using the -note variants:
[1, "@hat-note"]
[1, "@kick-note"]
[1, "@snare-note"]
[[1, "amp", "@set"], "@hat"]
[[1, "amp", "@set"], "@kick"]
[[1, "amp", "@set"], "@snare"]
[4, "@repeat", [
[["@iter", [0.3, 1]], "amp", "@set"],
8, "@repeat", ["@hat", 0.125, "@wait"]
]]
Repetition and parallelism
A list with several events normally happens at the same time:
[
[220, "freq", "@set"], "@pluck",
[330, "freq", "@set"], "@pluck"
]
Unless you add a n,@wait:
[
[220, "freq", "@set"], "@pluck",
1, "@wait",
[330, "freq", "@set"], "@pluck"
]
Here's how to do something a specific number of times:
[
4, "@repeat", [ "@pluck", 0.25, "@wait" ]
]
[
4, "@repeat", [ "@pluck", 0.25, "@wait" ],
[220, "freq", "@set"], "@pluck"
]
Here's how to do something forever:
[
"@loop", [ "@pluck", 0.25, "@wait" ]
]
Note that @loop will run the pattern that follows it in parallel, which means that you can keep on triggering more things after it. So it's easy to set up a bunch of parallel processes:
[
"@loop", [ 0.5, "@kick-note", 2, "@wait" ],
"@loop", [ 0.3, "@hat-note", 0.4, "@wait" ],
"@loop", [ 550, 0.5, "@pluck-note", 0.6, "@wait" ],
"@loop", [ 330, 0.4, "@pluck-note", 0.2, "@wait" ],
"@loop", [ 110, 0.6, "@pluck-note", 12, "@wait" ]
]
And to run something in parallel without looping it, just use @fork []:
[
"@loop", [
"@kick",
"@fork", [
0.25, "@wait",
550, 1, "@pluck-note",
0.33, "@wait",
660, 1, "@pluck-note"
],
1, "@wait"
]
]
This is also handy for setting up loops with different start times:
[
"@loop", ["@kick", 1, "@wait"],
"@fork", [0.5, "@wait",
"@loop", ["@hat", 1, "@wait"]
]
]
Expressions
Anywhere that a number would go, you can insert an expression. Here are some fun expressions.
Here's picking a value at random from a list, instead of giving the freq and amp values as numbers:
[
"@loop", [
["@pick", [330, 440, 550, 660]],
["@pick", [1, 0.7, 0.4]],
"@pluck-note",
0.25, "@wait"
]
]
Here's alternating between a set of values in a list, one at a time:
[
"@loop", [
["@iter", [330, 440, 550, 660]],
["@iter", [1, 0.2, 0.1]],
"@pluck-note",
0.25, "@wait"
]
]
Here's way to set the probability of something happening. Note that two lists have to be given after the "@chance"; either the first is run (if the chance happens), else the other one will be run.
[
"@loop", [
"@fork", [
0.2,
"@chance",
["@snare"],
["@tom"]
],
"@hat", 0.25, "@wait"
]
]
If you don't care about the 'else' case, just put an empty list [] or null. But you must put something, or else the virtual machine will get corrupted, and who knows what might happen.
[
"@loop", [
"@fork", [
0.1,
"@chance",
["@snare"],
[]
],
"@hat", 0.25, "@wait"
]
]
Another way of getting some randomness is to use the @rand (which generates a number between 0 and 1), @srand (which generates a number between -1 and 1), and n,@randi (which generates a number between 0 and n-1):
[
"@loop", [
"@rand", "amp", "@set",
"@pluck",
0.25, "@wait"
]
]
[
"@loop", [
"@pluck",
[3, "@randi"], "@wait"
]
]
There are several basic math functions that can be used to map numbers into useful ranges. Note that most math functions require the arguments first, e.g. use [a,b,@+] to add a and b:
[
"@loop", [
[[[4, "@randi"], 1, "@+"], 110, "@*"], "freq", "@set",
"@pluck",
0.25, "@wait"
]
]
[
"@loop", [
[["@srand", 10, "@*"], 110, "@+"], "freq", "@set",
"@pluck",
0.25, "@wait"
]
]
Get, set, and let
FIXME: this is no longer true. At this moment you can only use @set, @let or @get preceding the variable name
The @set-freq etc. are really just examples of creating named values ("variables") that can be re-used again later. Actually you can use @set-anything to create whatever variables you like, and use @get-anything to retrieve them. Mainly this is useful when you want to re-use something a few times:
[
"@loop", [
[[[4, "@randi"], 2, "@+"], 110, "@*"], "fq", "@set",
"fq", "@get", 0.6, "@pluck-note",
["fq", "@get", 1.5, "@mul"], 0.6, "@pluck-note",
0.25, "@wait"
]
]
By default @set-anything will apply globally, so you can modulate a parameter from one loop while using it in another:
[
"@loop", [
[[[4, "@randi"], 2, "@+"], 110, "@*"], "fq", "@set",
1, "@wait"
],
"@loop", [
"fq", "@get", 0.6, "@pluck-note",
["fq", "@get", 1.5, "@mul"], 0.6, "@pluck-note",
0.25, "@wait"
]
]
If globalism isn't what you care for, you can make a name "local" to a particular loop by using @let-anything. Once you have @let- a variable in a particular @loop (or @fork) pattern, it will remain local to that pattern. Generally, use @let if you want some value that is only used within a pattern, and @set if you want something global.
[
"@loop", [
[[[4, "@randi"], 1, "@+"], 110, "@mul"], "fq", "@let",
"fq", "@get", 0.6, "@pluck-note",
["fq", "@get", 1.5, "@mul"], 0.6, "@pluck-note",
0.25, "@wait"
],
"@loop", [
[[[4, "@randi"], 5, "@+"], 110, "@mul"], "fq", "@let",
"fq", "@get", 1, "@pluck-note",
["fq", "@get", 1.5, "@mul"], 0.6, "@pluck-note",
0.25, "@wait"
]
]
One use for this is to repeatedly modify a value, such as for a counter, or a decay:
[
"@loop", [
1, "a", "@let",
8, "@repeat", [
"a", "@get", "@snare-note",
0.25, "@wait",
"a", "@get", 0.6, "@*", "a", "@set"
]
]
]
The only thing special about @set-freq is that the name "freq" is used by @pluck. That is, @pluck is equivalent to: ["@get-freq", "@get-amp", "@pluck-note"]. Similarly for @set-amp etc.
Independently parallel
Say you want to be able to launch a loop, then let it keep running while you launch another. And say you want to redefine it while it plays, or stop it. To do that you need to name it. We can do that via "@spawn".
[
"foo", "@spawn", [220, 0.5, "@pluck-note", 0.50, "@wait"],
"bar", "@spawn", [330, 0.5, "@pluck-note", 0.75, "@wait"],
3, "@wait",
"foo", "@spawn", [110, 0.5, "@pluck-note", 1, "@wait"]
]
[
"foo", "@spawn", [440, 0.5, "@pluck-note", 0.5, "@wait"]
]
[
"bar", "@spawn", [110, 0.5, "@pluck-note", 1, "@wait"]
]
Click to change the "foo" part:
["foo", "@stop"]
[
"bar", "@stop"
]
[
"@loop",[
"@iter",[0.01,0.2,0.01],"@hat-note",
"@iter",[1,3],8,"@div","@wait"
],
"@loop",[
["@iter",[14,15,16,17,18],44,"@mul"],"freq", "@set",
0.1,"amp","@set",
"@pluck",
"@pick",[5,7],32,"@div","@wait"
],
"@loop",[
["@iter",[16,6,15,5,10,4,12],44,"@mul"],"freq", "@set",
1,"@pick",[2,3,5,6,5,6,5],"@div","amp", "@set",
"@pluck",
"@iter",[5,1,9,1],32,"@div","@wait"
]
]
Tempo and rate
There's a global tempo that can be manipulated:
[
0.4,"amp","@set",
"@loop",[
["@iter",[120, 80, 60]],"@set-bpm",4,"@wait"
],
"@loop",[
["@iter",[14,15,16,17,18],44,"@mul"],"freq","@set",
"@pluck", 0.25, "@wait"
],0.125,"@wait",
"@loop",[
["@iter",[32,34,36,24,30],44,"@mul"],"freq","@set",
"@pluck", 0.25, "@wait"
]
]
You can scale the current rate:
[
0.4,"amp","@set",
"@loop", [
["@iter",[14,15,16,17,18],44,"@mul"],"freq","@set",
"@pluck", 0.25, "@wait"
],
"@loop", [
["@iter",[14,15,16,17,18],66,"@mul"],"freq","@set",
"@pluck", 0.25, "@wait", 1.01, "@scale-rate"
]
]


Nools is a rete based rules engine written entirely in javascript.
npm install nools
Or download the source (minified)
When using nools you define a flow which acts as a container for rules that can later be used to get a session
var nools = require("nools");
var Message = function (message) {
this.text = message;
};
var flow = nools.flow("Hello World", function (flow) {
//find any message that start with hello
flow.rule("Hello", [Message, "m", "m.text =~ /^hello\\sworld$/"], function (facts) {
facts.m.text = facts.m.text + " goodbye";
this.modify(facts.m);
});
//find all messages then end in goodbye
flow.rule("Goodbye", [Message, "m", "m.text =~ /.*goodbye$/"], function (facts) {
console.log(facts.m.text);
});
});
In the above flow definition 2 rules were defined
text
must match the regular expression /^hello\\sworld$/
text
is modified and then we let the engine know that we modified the message.text
must match the regular expression /.*goodbye$/
(anything that ends in goodbye)You may also use the nools
rules language to define your rules.
The following is the equivalent of the rules defined programmatically above.
define Message {
text : '',
constructor : function(message){
this.text = message;
}
}
//find any message that starts with hello
rule Hello {
when {
m : Message m.text =~ /^hello(\s*world)?$/;
}
then {
modify(m, function(){this.text += " goodbye";});
}
}
//find all messages then end in goodbye
rule Goodbye {
when {
m : Message m.text =~ /.*goodbye$/;
}
then {
console.log(m.text);
}
}
To use the flow
var flow = nools.compile(__dirname + "/helloworld.nools"),
Message = flow.getDefined("message");
Each flow can have the following events emitted.
assert (fact)
- emitted when facts are assertedretract (fact)
- emitted when facts are retractedmodify (fact)
- emitted when facts are modifiedfire (name, rule)
- emitted when an activation is fired.session.on("assert", function(fact){
//fact was asserted
});
session.on("retract", function(fact){
//fact was retracted
});
session.on("modify", function(fact){
//fact was modifed
});
session.on("fire", function(name, rule){
//a rule was fired.
});
nools.compile
The compile method accepts the following parameters
source|path
- The first argument must either be a path that ends in .nools
or a string which is the source of the rules that you wish to compile.options?
name
: This is the name of the flow. You can use this name to look up the flow by using nools.getFlow
.define
: A hash of Classes that should be aviable to the rules that you are compiling.scope
: A hash of items that should be available to rules as they run. (i.e. a logger)cb?
- an options function to invoke when compiling is done.Example
rule "person name is bob" {
when {
p : Person p.name == 'bob';
}
then {
logger.info("Found person with name of bob");
retract(p);
}
}
In the above rules file we make use of a Person class and a logger. In order for nools to properly reference the Class and logger you must specify them in your options.
var flow = nools.compile("personFlow.nools", {
define: {
//The person class the flow should use
Person: Person
},
scope: {
//the logger you want your flow to use.
logger: logger
}
});
You may also compile source directly.
var noolsSource = "rule 'person name is bob' {"
+ " when {"
+ " p : Person p.name == 'bob';"
+ " }"
+ " then {"
+ " logger.info('Found person with name of bob');"
+ " retract(p);"
+ " }"
+ "}";
var flow = nools.compile(noolsSource, {
define: {
//The person class the flow should use
Person: Person
},
scope: {
//the logger you want your flow to use.
logger: logger
},
name: 'person name is bob'
});
A session is an instance of the flow that contains a working memory and handles the assertion, modification, and retraction of facts from the engine.
To obtain an engine session from the flow invoke the getSession
method.
var session = flow.getSession();
Facts are items that the rules should try to match.
To add facts to the session use assert
method.
session.assert(new Message("hello"));
session.assert(new Message("hello world"));
session.assert(new Message("goodbye"));
As a convenience any object passed into getSession will also be asserted.
Note assert is typically used pre engine execution and during the execution of the rules.
flow.getSession(new Message("hello"), new Message("hello world"), new Message("goodbye"));
To remove facts from the session use the retract
method.
var m = new Message("hello");
//assert the fact into the engine
session.assert(m);
//remove the fact from the engine
session.retract(m);
Note retract
is typically used during the execution of the rules.
To modify a fact use the modify
method.
Note modify will not work with immutable objects (i.e. strings).
var m = new Message("hello");
session.assert(m);
m.text = "hello goodbye";
session.modify(m);
Note modify
is typically used during the execution of the rules.
To get a list of facts currently in the session you can use the getFacts()
method exposed on a session.
session.assert(1);
session.assert("A");
session.assert("B");
session.assert(2);
session.getFacts(); //[1, "A", "B", 2];
You may also pass in a Type
to getFacts
which will return facts only of the given type.
session.assert(1);
session.assert("A");
session.assert("B");
session.assert(2);
session.getFacts(Number); //[1, 2];
session.getFacts(String); //["A", "B"];
When you get a session from a flow no rules will be fired until the match method is called.
var session = flow.getSession();
//assert your different messages
session.assert(new Message("goodbye"));
session.assert(new Message("hello"));
session.assert(new Message("hello world"));
//now fire the rules
session.match(function(err){
if(err){
console.error(err.stack);
}else{
console.log("done");
}
})
The match method also returns a promise that is resolved once there are no more rules to activate.
session.match().then(
function(){
console.log("Done");
},
function(err){
//uh oh an error occurred
console.error(err.stack);
});
You may also run the engine an a "reactive" mode which will continue to match until halt
is invoked.
In the following example the rules engine continues to evaluate until the counter reaches 10000
. If you remove the "counted to high" rule then the engine would run indefinitely.
define Counter {
count: 0,
constructor: function(count){
this.count = count;
}
}
//We reached our goal
rule "I can count!" {
when {
$ctr: Counter $ctr.count == 10000;
}
then{
console.log("Look ma! I counted to " + $ctr.count);
halt();
}
}
//no counter was asserted so create one
rule "not count" {
when {
not($ctr: Counter);
}
then{
console.log("Imma gonna count!");
assert(new Counter(1));
}
}
//A little status update
rule "give them an update" {
when{
$ctr: Counter $ctr.count % 1000 == 0 {count: $count}
}
then{
console.log("Imma countin...");
modify($ctr, function(){this.count = $count + 1;});
}
}
//just counting away
rule count {
when{
$ctr: Counter {count: $count}
}
then{
modify($ctr, function(){
this.count = $count + 1;
});
}
}
flow.getSession().matchUntilHalt(function(err){
if(err){
console.log(err.stack);
return;
}
//halt finally invoked
});
matchUntilHalt
also returns a promise.
flow.getSession().matchUntilHalt()
.then(
function(){
//all done!
},
function(err){
console.log(err.stack);
}
);
When working with a lot of facts it is wise to call the dispose
method which will purge the current session of
all facts, this will help prevent the process from growing a large memory footprint.
session.dispose();
To remove a defined flow from nools
use the deleteFlow
function.
var myFlow = nools.flow("flow");
nools.deleteFlow("flow"); //returns nools for chaining
nools.getFlow("flow"); //undefined
You may also remove a flow using the FlowContainer
object returned from nools.flow;
var myFlow = nools.flow("flow");
nools.deleteFlow(myFlow); //returns nools for chaining
nools.getFlow("flow"); //undefined
To remove all flow from nools
use the deleteFlows
function.
var myFlow = nools.flow("flow");
nools.deleteFlows(); //returns nools for chaining
nools.getFlow("flow"); //undefined
To check if a flow currently is registering with nools
use the hasFlow
function;
var myFlow = nools.flow("flow");
nools.hasFlow("flow"); //true
Agenda groups allow for logical groups of rules within a flow.
The agenda manages a stack
of agenda-groups
that are currently in focus. The default agenda-group
is called main
and all rules that do not have an agenda-group
specified are placed into the main
agenda-group
.
As rules are fired and a particular agenda-group
runs out of activations then that agenda-group
is popped from the internal agenda-group
stack and the next one comes into focus. This continues until focus
is explicitly called again or the main
agenda-group
comes into focus.
Note Once an agenda group loses focus it must be re-added to the stack in order for those activations to be focused again.
To add a rule to an agenda-group you can use the agendaGroup
option.
this.rule("Hello World", {agendaGroup: "ag1"}, [Message, "m", "m.name == 'hello'"], function (facts) {
this.modify(facts.m, function () {
this.name = "goodbye";
});
});
this.rule("Hello World2", {agendaGroup: "ag2"}, [Message, "m", "m.name == 'hello'"], function (facts) {
this.modify(facts.m, function () {
this.name = "goodbye";
});
});
Or in the dsl
rule "Hello World" {
agenda-group: "ag1";
when{
m : Message m.name === 'hello';
}
then{
modify(m, function(){
this.name = "goodbye";
});
}
}
rule "Hello World 2" {
agenda-group: "ag2";
when{
m : Message m.name === 'goodbye';
}
then {
modify(m, function(){
m.name = "hello";
});
}
}
In the above rules we have defined two agenda-groups called ag1
and ag2
When running your rules and you want a particular agenda group to run you must call focus
on the session of the flow and specify the agenda-group
to add to the stack.
//assuming a flow with the rules specified above.
var fired = [];
flow.getSession(new Message("hello"))
.focus("ag1")
.on("fire", function (ruleName) {
fired.push(ruleName);
})
.match(function () {
console.log(fired); //[ 'Hello World' ]
});
Or you can add multiple agenda-groups
to the focus stack.
var fired1 = [], fired2 = [];
flow
.getSession(new Message("goodbye"))
.focus("ag1")
.focus("ag2")
.on("fire", function (ruleName) {
fired1.push(ruleName);
})
.match(function () {
console.log("Example 1", fired1); //[ 'Hello World', 'Hello World2' ]
});
flow
.getSession(new Message("hello"))
.focus("ag2")
.focus("ag1")
.on("fire", function (ruleName) {
fired3.push(ruleName);
})
.match(function () {
console.log("Example 2", fired2); //[ 'Hello World', 'Hello World2' ]
});
Notice above that the last agenda-group
focused is added to the array first.
Sometimes you may want an agenda-group
to auto-focus
whenever a certain rule is activated.
this.rule("Bootstrap", [State, "a", "a.name == 'A' && a.state == 'NOT_RUN'"], function (facts) {
this.modify(facts.a, function () {
this.state = 'FINISHED';
});
});
this.rule("A to B",
[
[State, "a", "a.name == 'A' && a.state == 'FINISHED'"],
[State, "b", "b.name == 'B' && b.state == 'NOT_RUN'"]
],
function (facts) {
this.modify(facts.b, function () {
this.state = "FINISHED";
});
});
this.rule("B to C",
{agendaGroup: "B to C", autoFocus: true},
[
[State, "b", "b.name == 'B' && b.state == 'FINISHED'"],
[State, "c", "c.name == 'C' && c.state == 'NOT_RUN'"]
],
function (facts) {
this.modify(facts.c, function () {
this.state = 'FINISHED';
});
this.focus("B to D");
});
this.rule("B to D",
{agendaGroup: "B to D"},
[
[State, "b", "b.name == 'B' && b.state == 'FINISHED'"],
[State, "d", "d.name == 'D' && d.state == 'NOT_RUN'"]
],
function (facts) {
this.modify(facts.d, function () {
this.state = 'FINISHED';
});
});
Or using the dsl
rule Bootstrap {
when{
a : State a.name == 'A' && a.state == 'NOT_RUN';
}
then{
modify(a, function(){
this.state = 'FINISHED';
});
}
}
rule 'A to B' {
when{
a : State a.name == 'A' && a.state == 'FINISHED';
b : State b.name == 'B' && b.state == 'NOT_RUN';
}
then{
modify(b, function(){
this.state = 'FINISHED';
});
}
}
rule 'B to C' {
agenda-group: 'B to C';
auto-focus: true;
when{
b: State b.name == 'B' && b.state == 'FINISHED';
c : State c.name == 'C' && c.state == 'NOT_RUN';
}
then{
modify(c, function(){
this.state = 'FINISHED';
});
focus('B to D')
}
}
rule 'B to D' {
agenda-group: 'B to D';
when{
b: State b.name == 'B' && b.state == 'FINISHED';
d : State d.name == 'D' && d.state == 'NOT_RUN';
}
then{
modify(d, function(){
this.state = 'FINISHED';
});
}
}
In the above rules we created a state machine that has a rule with auto-focus
set to true.
This allows you to not have to specify focus
when running the flow.
var fired = [];
flow
.getSession(
new State("A", "NOT_RUN"),
new State("B", "NOT_RUN"),
new State("C", "NOT_RUN"),
new State("D", "NOT_RUN")
)
.on("fire", function (name) {
fired.push(name);
})
.match()
.then(function () {
console.log(fired); //["Bootstrap", "A to B", "B to C", "B to D"]
});
When declaring a flow it is defined with a default conflict resolution strategy. A conflict resolution strategy is used to determine which rule to activate when multiple rules are ready to be activated at the same time.
salience
- sort activations on the specified salience
. (NOTE The default salience of a rule is 0).activationRecency
- sort activations on activation recency. This is a LIFO
strategy the latest activation takes precedence.factRecency
- sort activations based on fact
recency. Each time a fact is asserted
or modified
its recency is incremented.bucketCounter
- sort activations on the internal bucket
counter. The bucket counter is incremented after an activation is fired and the internal workingMemory
is altered.The default conflict resolution strategy consists of salience
and activationRecency
.
Example 1
//activation 1
{
salience: 0,
activationRecency: 1
}
//activation 2
{
salience: 0,
activationRecency: 2
}
In the above example activation 2 would be fired since it is the most recent activation and the rule salience is the same.
Example 2
//activation 1
{
salience: 1,
activationRecency: 1
}
//activation 2
{
salience: 0,
activationRecency: 2
}
In this example activation 1 would fire because it has a greater salience
To override the default strategy you can use the conflictResolution
method on a flow.
var flow = nools.flow(/**define your flow**/);
flow.conflictResolution(["salience", "factRecency", "activationRecency"]);
The combination of salience
, factRecency
, and activationRecency
would do the following.
Example 1
//activation 1
{
salience: 2,
factRecency: [1,2,3],
activationRecency: 1
}
//activation 2
{
salience: 1,
factRecency: [1,2,4],
activationRecency: 2
}
In this example activation 1 would fire because it's salience is the greatest.
Example 2
//activation 1
{
salience: 1,
factRecency: [1,2,3],
activationRecency: 1
}
//activation 2
{
salience: 1,
factRecency: [1,2,4],
activationRecency: 2
}
In Example 2 activation 2 would fire because of the third recency entry.
Example 3
//activation 1
{
salience: 2,
factRecency: [1,2,3],
activationRecency: 1
}
//activation 2
{
salience: 1,
factRecency: [1,2,3],
activationRecency: 2
}
In Example 3 activation 2 would fire because salience
and factRecency
are the same but activation 2's activation recency is greater.
Lets look at the "Calculate" rule in the Fibonacci example
//flow.rule(type[String|Function], constraints[Array|Array[[]]], action[Function]);
flow.rule("Calculate", [
//Type alias pattern store sequence to s1
[Fibonacci, "f1", "f1.value != -1", {sequence:"s1"}],
[Fibonacci, "f2", "f2.value != -1 && f2.sequence == s1 + 1", {sequence:"s2"}],
[Fibonacci, "f3", "f3.value == -1 && f3.sequence == s2 + 1"],
[Result, "r"]
], function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
});
Or using the nools DSL
rule Calculate{
when {
f1 : Fibonacci f1.value != -1 {sequence:s1};
f2 : Fibonacci f2.value != -1 && f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 && f3.sequence == s2 + 1;
}
then {
modify(f3, function(){
this.value = f1.value + f2.value;
});
retract(f1);
}
}
Salience is an option that can be specified on a rule giving it a priority and allowing the developer some control over conflict resolution of activations.
this.rule("Hello4", {salience: 7}, [Message, "m", "m.name == 'Hello'"], function (facts) {
});
this.rule("Hello3", {salience: 8}, [Message, "m", "m.name == 'Hello'"], function (facts) {
});
this.rule("Hello2", {salience: 9}, [Message, "m", "m.name == 'Hello'"], function (facts) {
});
this.rule("Hello1", {salience: 10}, [Message, "m", "m.name == 'Hello'"], function (facts) {
});
Or using the DSL
rule Hello4 {
salience: 7;
when {
m: Message m.name == 'hello';
}
then {}
}
rule Hello3 {
salience: 8;
when {
m: Message m.name == 'hello';
}
then {}
}
rule Hello2 {
salience: 9;
when {
m: Message m.name == 'hello';
}
then {}
}
rule Hello1 {
salience: 10;
when {
m: Message m.name == 'hello';
}
then {}
}
In the above flow we define four rules each with a different salience, when a single message is asserted they will fire in order of salience (highest to lowest).
var fired = [];
flow1
.getSession(new Message("Hello"))
.on("fire", function (name) {
fired.push(name);
})
.match()
.then(function(){
console.log(fired); //["Hello1", "Hello2", "Hello3", "Hello4"]
});
Scope allows you to access function from within your rules.
If you are using vanilla JS you can use the scope
option when defining your rule.
this.rule("hello rule", {scope: {isEqualTo: isEqualTo}},
[
["or",
[String, "s", "isEqualTo(s, 'hello')"],
[String, "s", "isEqualTo(s, 'world')"]
],
[Count, "called", null]
],
function (facts) {
facts.called.called++;
});
If you are using the dsl.
function matches(str, regex){
return regex.test(str);
}
rule Hello {
when {
m : Message matches(m.text, /^hello\s*world)?$/);
}
then {
modify(m, function(){
this.text += " goodbye";
})
}
}
rule Goodbye {
when {
m : Message matches(m.text, /.*goodbye$/);
}
then {
}
}
Or you can pass in a custom function using the scope option in compile.
rule Hello {
when {
m : Message doesMatch(m.text, /^hello\sworld$/);
}
then {
modify(m, function(){
this.text += " goodbye";
})
}
}
rule Goodbye {
when {
m : Message doesMatch(m.text, /.*goodbye$/);
}
then {
}
}
Provided the doesMatch
function in the scope option of compile.
function matches(str, regex) {
return regex.test(str);
};
var flow = nools.compile(__dirname + "/rules/provided-scope.nools", {scope: {doesMatch: matches}});
Constraints define what facts the rule should match. The constraint is a array of either a single constraint (i.e. Bootstrap rule) or an array of constraints(i.e. Calculate).
Programmatically
[
//Type alias pattern store sequence to s1
[Fibonacci, "f1", "f1.value != -1", {sequence:"s1"}],
[Fibonacci, "f2", "f2.value != -1 && f2.sequence == s1 + 1", {sequence:"s2"}],
[Fibonacci, "f3", "f3.value == -1 && f3.sequence == s2 + 1"],
[Result, "r"]
]
Using nools DSL
when {
f1 : Fibonacci f1.value != -1 {sequence:s1};
f2 : Fibonacci f2.value != -1 && f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 && f3.sequence == s2 + 1;
r : Result;
}
String
- "string", "String", StringNumber
- "number", "Number", NumberBoolean
- "boolean", "Boolean", BooleanDate
- "date", "Date", DateRegExp
- "regexp", "RegExp", RegExpArray
- "array", "Array", [], ArrayObject
- "object", "Object", "hash", ObjectPattern(optional) - The pattern that should evaluate to a boolean, the alias that was used should be used to reference the object in the pattern. Strings should be in single quotes, regular expressions are allowed. Any previously defined alias/reference can be used within the pattern. Available operators are.
&&
, AND
, and
||
, OR
, or
>
, <
, >=
, <=
, gt
, lt
, gte
, lte
==
, ===
, !=
, !==
, =~
, !=~
, eq
, seq
, neq
, sneq
, like
, notLike
+
, -
, *
, /
, %
-
(unary minus).
(member operator)in
(check inclusion in an array)notIn
(check that something is not in an array)now
- the current dateDate(year?, month?, day?, hour?, minute?, second?, ms?)
- creates a new Date
objectlengthOf(arr, length)
- checks the length of an arrayisTrue(something)
- check if something === trueisFalse(something)
- check if something === falseisRegExp(something)
- check if something is a RegExp
isArray(something)
- check if something is an Array
isNumber(something)
- check if something is an Number
isHash(something)
- check if something is strictly an Object
isObject(something)
- check if something is any type of Object
isDate(something)
- check if something is a Date
isBoolean(something)
- check if something is a Boolean
isString(something)
- check if something is a String
isUndefined(something)
- check if something is a undefined
isDefined(something)
- check if something is Defined
isUndefinedOrNull(something)
- check if something is a undefined
or null
isPromiseLike(something)
- check if something is a "promise" like (containing then
, addCallback
, addErrback
)isFunction(something)
- check if something is a Function
isNull(something)
- check if something is null
isNotNull(something)
- check if something is not nulldateCmp(dt1, dt2)
- compares two dates return 1, -1, or 0(years|months|days|hours|minutes|seconds)(Ago|FromNow)(interval)
- adds/subtracts the date unit from the current timeReference(optional) - An object where the keys are properties on the current object, and values are aliases to use. The alias may be used in succeeding patterns.
When declaring your rules progrmmatically you can also use a function as a constraint. The function will be called with an object containing each fact that has matched previous constraints.
var HelloFact = declare({
instance: {
value: true,
constructor: function (value) {
this.value = value;
}
}
});
var flow = nools.flow("custom contraint", function (flow) {
flow.rule("hello rule", [HelloFact, "h", function (facts) {
return facts.h.value === true;
}], function (facts) {
console.log(facts.h.value); //always true
});
});
var session = flow.getSession();
session.assert(new HelloFact(false));
session.assert(new HelloFact(true));
session.match().then(function(){
console.log("DONE");
});
The not
constraint allows you to check that particular fact
does not exist.
[
[Number, "n1"],
["not", Number, "n2", "n1 > n2"]
]
Or using the DSL.
when {
n1: Number;
not(n2: Number n1 > n2);
}
The previous example will check that for all numbers in the workingMemory
there is not one that is greater than n1
.
The or
constraint can be used to check for the existence of multiple facts.
[
["or",
[String, "s", "s == 'hello'"],
[String, "s", "s == 'world'"],
[String, "s", "s == 'hello world'"]
]
]
Using the DSL.
when {
or(
s : String s == 'hello',
s : String s == 'world',
s : String s == 'hello world'
);
}
The previous example will evaluate to true
if you have a string in workingMemory
that equals hello
, world, or 'hello world
.
Or with Not
The or
constraint can be combined with a not
constraint to allow for the checking of multiple not conditions without the implcit and.
var flow = nools.flow("or condition with not conditions", function (flow) {
flow.rule("hello rule", [
["or",
["not", Number, "n1", "n1 == 1"],
["not", String, "s1", "s1 == 'hello'"],
["not", Date, "d1", "d1.getDate() == now().getDate()"]
],
[Count, "called", null]
], function (facts) {
facts.called.called++;
});
});
});
or using the dsl.
rule MultiNotOrRule {
when {
or (
not(n1: Number n1 == 1),
not(s1: String s1 == 'hello'),
not(d1: Date d1.getDate() == now().getDate())
);
c: Count;
}
then{
c.called++;
}
}
Note Using the or
with a not
will cause the activation to fire for each not
condition that passes. In the above examples if none of the three facts existed then the rule would fire three times.
The from
modifier allows for the checking of facts that are not necessarily in the workingMemory
.
The from
modifier can be used to access properties on a fact
in workingMemory
or you can use javascript expressions.
To access properties on a fact you can use the fact name and the property you wish to use as the source for the from
source.
[
[Person, "p"],
[Address, "a", "a.zipcode == 88847", "from p.address"],
[String, "first", "first == 'bob'", "from p.firstName"],
[String, "last", "last == 'yukon'", "from p.lastName"]
]
Or using the DSL.
when {
p: Person:
a: Address a.zipcode == 88847 from p.address;
first: String first == 'bob' from p.firstName;
last: String last == 'yukon' from p.lastName;
}
The above example will used the address, firstName and lastName from the person
fact.
You can also use the from
modifier to check facts that create a graph.
For example assume the person object from above has friends that are also of type Person
.
[
[Person, "p"],
[Person, "friend", "friend.firstName != p.firstName", "from p.friends"],
[String, "first", "first =~ /^a/", "from friend.firstName"]
]
Or using the DSL.
when {
p: Person;
friend: Person friend.firstName != p.firstName from p.friends;
first: String first =~ /^a/ from friend.firstName;
}
The above example will pull the friend
fact from the friends array property on fact p
, and first from the friend
's firstName
.
You could achieve the same thing using the following code if you assert all friends into working memory.
when {
p: Person;
friend: Person friend in p.friends && friend.firstName != p.firstName && p.firstName =~ /^a/;
}
To specify the from source as an expression you can do the following.
[
[Number, "n1", "from [1,2,3,4,5]"]
]
Or using the dsl
{
n1: Number from [1,2,3,4,5];
}
Using the above syntax you could use from
to bootstrap data.
You can also use any function defined in the scope of the rule
or flow
flow.rule("my rule", {
scope: {
myArr: function(){
return [1,2,3,4,5];
}
},
[Number, "n1", "from myArr()"],
function(facts){
this.assert(facts.n1);
}
}
Or using the dsl and the scope option.
rule "my rule", {
when {
n1: Number from myArr();
}
then{
assert(n1);
}
}
exists
is the logical inversion of a not
constraint. It checks for the existence of a fact in memory.
NOTE If there are multiple facts that satisfy the constraint the rule will ONLY be fired once.
[
["exists", Number, "n1", "n1 > 1"]
]
Or using the DSL.
when {
exists(n1: Number n1 > 1);
}
Assuming the above constraint. The following facts would cause the rule to fire once since there is a number that is greater than 1.
session.assert(1);
session.assert(2);
session.assert(3);
session.assert(4);
session.assert(5);
The action is a function that should be fired when all patterns in the rule match. The action is called in the scope
of the engine so you can use this
to assert
, modify
, or retract
facts. An object containing all facts and
references created by the alpha nodes is passed in as the first argument to the action.
So calculate's action modifies f3 by adding the value of f1 and f2 together and modifies f3 and retracts f1.
function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
}
The session is also passed in as a second argument so alternatively you could do the following.
function (facts, session) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
session.modify(f3);
session.retract(f1);
}
To define the actions with the nools DSL
then {
modify(f3, function(){
this.value = f1.value + f2.value;
});
retract(f1);
}
For rules defined using the rules language nools will automatically determine what parameters need to be passed in based on what is referenced in the action.
If your action is async you can use the third argument which should be called when the action is completed.
function (facts, engine, next) {
//some async action
process.nextTick(function(){
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
engine.modify(f3);
engine.retract(f1);
next();
});
}
If an error occurs you can pass the error as the first argument to next
.
then{
saveToDatabase(user, function(err){
next(new Error("Something went BOOM!"));
});
}
If you are using a Promises/A+
compliant library you can just return a promise from your action and nools
will wait for the promise to resolve before continuing.
then{
return saveToDatabase(user); // assume saveToDatabase returns a promise
}
Globals are accessible through the current working scope of rules defined in a dsl
, very similar to using the scope
option when compiling.
Note globals
are not part of the working memory and therefore are not accessible in the LHS (when) or your rule.
Globals are used like the following:
global PI = Math.PI;
global SOME_STRING = 'some string';
global TRUE = true;
global NUM = 1.23;
global DATE = new Date();
rule "A Rule" {
when {
$obj: Object;
}
then{
console.log(PI); //Math.PI;
console.log(SOME_STRING); //"some string"
console.log(TRUE); //true
console.log(NUM); //1.23
console.log(DATE); //Thu May 23 2013 15:49:22 GMT-0500 (CDT)
}
}
If you are using nools
in node
you can also use a require statement.
NOTE require does not currently work for relative paths.
global util = require("util");
rule "A Rule" {
when {
$obj: Object;
}
then{
util.log("HELLO WORLD");
}
}
The import
statement allows you to import other nools
files into the current one. This can be used to split up logical flows into small reusable groups of rules.
Define our common model to be used across our flows.
//define.nools
define Count{
constructor: function(){
this.called = 0;
}
}
Create a rules file which imports the define.nools
to define our Count
model.
//orRule.nools
//import define.nools
import("./define.nools");
rule orRule {
when {
or(
s : String s == 'hello',
s : String s == 'world'
);
count : Count;
}
then {
count.called++;
count.s = s;
}
}
Same as orRule.nools
import our define.nools
//notRule.nools
import("./defines.nools");
rule notRule {
when {
not(s : String s == 'hello');
count : Count
}
then {
count.called++;
}
}
Now we can use orRule.nools
and notRule.nools
to compose a new flow that contains define.nools
, orRule.nools
and notRule.nools
.
Note nools
will handle duplicate imports, in this case define.nools
will only be imported once.
//import
import("./orRules.nools");
import("./notRules.nools");
You may also emit events from your rule actions using the sessions emit function.
then {
modify(f3, function(){
this.value = f1.value + f2.value;
});
retract(f1);
emit("my custom event");
}
To listen to the event just use the on method of the session.
var session = flow.getSession();
session.on("my custom event", function(){
//custom event called.
});
Nools
can also be used in the browser. The only difference is that you cannot pass a file location to the compile method instead you must provide the source.
Nools is compatible with amd(requirejs) and can also be used in a standard script tag.
In this example we compile rules definitions inlined in a script tag.
<script type="text/javascript" src="nools.js"></script>
<script type="text/nools" id="simple">
define Message {
message : "",
constructor : function (message) {
this.text = message;
}
}
rule Hello {
when {
m : Message m.text =~ /^hello\sworld$/
}
then {
modify(m, function(){
this.text += " goodbye";
});
}
}
rule Goodbye {
when {
m : Message m.text =~ /.*goodbye$/
}
then {
document.getElementById("output").innerHTML += m.text + "</br>";
}
}
</script>
<script type="text/javascript">
function init() {
//get the source
var source = document.getElementById("simple").innerHTML;
//compile the source. The name option is required if compiling directly.
var flow = nools.compile(source, {name: "simple"}),
Message = flow.getDefined("message"),
session = flow.getSession();
//assert your different messages
session.assert(new Message("goodbye"));
session.assert(new Message("hello world"));
session.match();
}
</script>
You may also use the nools
executable to compile source into a browser friendly format skipping the need for compiling each time.
nools compile ./my/rules.nools > ./compiled.js
To use the flow require the compile version either through a script tag, amd/requirejs
, or commonjs
require.
If you import the flow using a script tag you can get a reference to the flow by using nools.getFlow
.
nools.getFlow("rules");
You may also specify the name of the flow when compiling, it defaults to the name of the nools file less ".nools"
nools compile -n "my rules" ./my/rules.nools
nools.getFlow("my rules");
If you are using requirejs or nools must be required using something other than require("nools")
then you can specify a location of the nools source.
nools compile -nl "./location/to/nools" ./my/rules.nools
Examples of using nools with require js are located in the examples directory.
"use strict";
var nools = require("nools");
var Fibonacci = function (sequence, value) {
this.sequence = sequence;
this.value = value || -1;
};
var Result = function (result) {
this.result = result || -1;
};
var flow = nools.flow("Fibonacci Flow", function (flow) {
flow.rule("Recurse", [
["not", Fibonacci, "f", "f.sequence == 1"],
[Fibonacci, "f1", "f1.sequence != 1"]
], function (facts) {
var f2 = new Fibonacci(facts.f1.sequence - 1);
this.assert(f2);
});
flow.rule("Bootstrap", [
Fibonacci, "f", "f.value == -1 && (f.sequence == 1 || f.sequence == 2)"
], function (facts) {
var f = facts.f;
f.value = 1;
this.modify(f);
});
flow.rule("Calculate", [
[Fibonacci, "f1", "f1.value != -1", {sequence:"s1"}],
[Fibonacci, "f2", "f2.value != -1 && f2.sequence == s1 + 1", {sequence:"s2"}],
[Fibonacci, "f3", "f3.value == -1 && f3.sequence == s2 + 1"],
[Result, "r"]
], function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
});
});
var r1 = new Result(),
session1 = flow.getSession(new Fibonacci(10), r1),
s1 = new Date;
session1.match().then(function () {
console.log("%d [%dms]", r1.result, new Date - s1);
session1.dispose();
});
var r2 = new Result(),
session2 = flow.getSession(new Fibonacci(150), r2),
s2 = new Date;
session2.match().then(function () {
console.log("%d [%dms]", r2.result, new Date - s2);
session2.dispose();
});
var r3 = new Result(),
session3 = flow.getSession(new Fibonacci(1000), r3),
s3 = new Date;
session3.match().then(function () {
console.log("%d [%dms]", r3.result, new Date - s3);
session3.dispose();
});
Output
55 [43ms]
9.969216677189305e+30 [383ms]
4.346655768693743e+208 [3580ms]
//Define our object classes, you can
//also declare these outside of the nools
//file by passing them into the compile method
define Fibonacci {
value:-1,
sequence:null
}
define Result {
value : -1
}
rule Recurse {
when {
//you can use not or or methods in here
not(f : Fibonacci f.sequence == 1);
//f1 is how you can reference the fact else where
f1 : Fibonacci f1.sequence != 1;
}
then {
assert(new Fibonacci({sequence : f1.sequence - 1}));
}
}
rule Bootstrap {
when {
f : Fibonacci f.value == -1 && (f.sequence == 1 || f.sequence == 2);
}
then{
modify(f, function(){
this.value = 1;
});
}
}
rule Calculate {
when {
f1 : Fibonacci f1.value != -1 {sequence : s1};
//here we define constraints along with a hash so you can reference sequence
//as s2 else where
f2 : Fibonacci f2.value != -1 && f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 && f3.sequence == s2 + 1;
r : Result
}
then {
modify(f3, function(){
this.value = r.result = f1.value + f2.value;
});
retract(f1);
}
}
And to run
var flow = nools.compile(__dirname + "/fibonacci.nools");
var Fibonacci = flow.getDefined("fibonacci"), Result = flow.getDefined("result");
var r1 = new Result(),
session1 = flow.getSession(new Fibonacci({sequence:10}), r1),
s1 = +(new Date());
session1.match().then(function () {
console.log("%d [%dms]", r1.result, +(new Date()) - s1);
session1.dispose();
});
var r2 = new Result(),
session2 = flow.getSession(new Fibonacci({sequence:150}), r2),
s2 = +(new Date());
session2.match().then(function () {
console.log("%d [%dms]", r2.result, +(new Date()) - s2);
session2.dispose();
});
var r3 = new Result(),
session3 = flow.getSession(new Fibonacci({sequence:1000}), r3),
s3 = +(new Date());
session3.match().then(function () {
console.log("%d [%dms]", r3.result, +(new Date()) - s3);
session3.dispose();
});
MIT https://github.com/C2FO/nools/raw/master/LICENSE
git clone git://github.com/C2FO/nools.git


Candidate Profile
| Name | Barry Edwards |
| Party | Independent |
|<EMAIL_ADDRESS>|
Background
Tell us about your education?
- 5 ‘O’ Levels
- 2 ‘A’ Levels Environmental Studies ‘C’, Geography ‘E’
- Dip H/E Environmental Science
- B.Sc. Environmental Science
What are three jobs you have held?
- Curator — River Thames Visitor Centre — New Project - Richmond
- Business owner — St Margarets Landscaping — 15 years in St Margarets
- Assistant Publisher — Trade Computer Journal — Richmond — 4 years
What are you links to the North Twickenham/St Margarets community?
I grew up on the Somerset Levels, a farming community and an area of outstanding natural beauty. This experience together with my father’s passion for gardening was the spark for my curiosity in understanding man and his environment. I then worked for the Nature Conservancy Council (now called English Nature) and qualified to Scientific Officer Grade within the Civil Service.
When I moved to London and tried sales work. I was successful and developed people and negotiation skills. This lead to starting a family based business working almost exclusively for the people of St Margarets. I have learnt many things as I have gone about my work, being active as a member of local voluntary groups, taking part in public consultations, appeals to get my child into local schools and developing my own projects (involving planning applications).
I am a member of St Margarets Traders, St Margarets Residents Association and Chairman of the local River Thames Society Branch.
I am also on the Mayor of London’s, London Waterway Commission, advising on the implementation of the London plan.
Why did/do you want to be a councilor?
I would like to be a Councilor because a) I was asked by the St Margarets Traders/St Margarets residents and b) over the years, my experience of living in St Margarets has taught me that the party political system was not correctly representing local people. The party political view always seemed to be put before that of the local residents.
Issues
What do you think are the top three issues for North Twickenham/St Margarets and what do you should be done about them?
The political parties will use single issues e.g. green issues, safety or education to state how they will beat each other, but if you want the truth, it is not about a child-like party political fight. Important issues are always less likely to catch a head-line, or a sound bite, but usually they are the ones which should receive most focus.
- The adoption of active public consultation, in line with the requirements on the Local Development Framework. (The most important issue affecting the future of St Margarets). There is a condition in the new LDF legislation which must have a “statement of community involvement”. This is a contract between the local people and the Council regarding how the community should develop. I went to the initial Council consultations and found that the views of local representatives and residents were not being adequately incorporated. I will be interested to know how many website visitors are aware of this, or have been asked about the future of St Margarets in the LDF by political parties?
Suggestion: I will have regular surgeries and rigorously examine the future Council proposals to ensure local community needs are incorporated within the LDF. - The examination of infrastructure projects, inc new homes. We have to start looking at planning applications in terms of whether we have the school capacity for the children from new housing developments, the available sewage treatment capacity to avoid pubic health issues, the roads to cope with the increases in traffic movements etc.
Local residents are being forced by planning applications to suffer a reduced quality of life by increasing numbers of these projects. We cannot go forward with the current numbers of school appeals, traffic congestion and public health issues because of over-development.
Suggestion: I will have regular meetings with - School Governors (re: numbers of appeals) and look at providing new schools — Consult with Highway planners to keep St Margarets moving (particularly putting yellow “keep clear” boxes on the A316 roundabout) and continue my work to ensure Mogden keeps within the conditions of its Abatement Notice and that further pressure is not placed on its limited sewage treatment capacity. - To improve the fabric of St Margarets. We have huge problems in using the essential shops and services. There are very few sites for recycling. Community events have not been adequately encouraged and open spaces and areas of architectural interest are under threat by unreasonable planning applications in Conservation Areas.
St Margarets needs to be assessable. It needs 30 mins free parking for residents. In fact residents permits should be free, to stop commuters parking, but without financially hitting the local people. Business should not be charged for visiting our homes to do essential work. The Council should not charge Crown Road Community events for road closures and the organizers should have an increase in their community grant. We all love these events, let’s support them. St Margarets Traders should be able to manage its recycling initiative. I cannot understand the current difficulty. Development proposals should meet the highest ideals of Conservation Area Statements to protect open spaces and historic buildings.
What areas are you passionate about and what committees would you like to sit on?
I am passionate about keeping St Margarets an enjoyable and unique place to live. I live in St Margarets and the residents are best qualified and the hardest workers trying to build this community. I wish to be available and answerable only to them. As an Independent I am not bound by party political interests, so I will be able achieve the aims of the community without this political bias.
I would therefore like to sit on the Environment, LDF and Finance Committees to bring professional and local community scrutiny to Council plans and how our money is spent.
Are there any big things you are looking to achieve or change?
I would like to achieve a better level of democracy of a similar type to that achieved by Elmbridge Borough Council. For the last 25 years the Council has been controlled by Independent Councilors nominated by their own local Residents Associations. This has ensured that local community priorities come first. This would remove the party political spin we have come to expect from the current system.
If elected, how will you keep in-touch with your constituents?
I have already covered this, but I will further say that I will offer a level of availability and creativity for community issues never offered before. I will work with all local groups and this website to offer regular and an active consultation network.
Fun
What is your favorite musical group/band/cd?
I enjoy trying to write music and far too infrequently performing, mainly rock/folk. But I love the song “Knights in White Satin”, if only for the line “some try to tell me thoughts, they cannot defend”
What is your favorite book?
Again, I enjoy participation and have written a book called “How to have an easy life”. But I do like the work of Chekov. His words paint pictures in the mind as vivid as being at the cinema.
What is the last book you read?
The Marine Bill. A consultation document of the Department for Environment, Food and Rural Affairs. Yes it is really is a book 312 pages!!
What are three places you have lived?
As well as the places mentioned I have also lived in:
- Liverpool
- Crewe
- Newton Abbot.
What is your favorite meal?
Mature organic roast beef from a Soil Association Supplier, food carefully produced and tastes superb.
What is your favorite place to take a holiday?
Lake Balaton in Hungary


Burkina Faso has been reporting an increase in the number of dengue fever cases in health facilities since week 31 of 2017 (week ending on 6 August 2017). The Ministry of Health officially declared the outbreak on 28 September 2017.
As of 3 November 2017, a total of 9 029 (suspected, probable or confirmed) cases and 18 deaths (CFR= 0.2%) were reported throughout the country. Of the total cases reported, 5773 (64%) were probable, with a positive result for dengue by the rapid diagnostic test (RDT). During week 43 of 2017, 2 566 cases (including 1427 probable) were reported across all regions.
Out of 241 samples referred for PCR testing at the Viral Haemorrhagic fever (VHF) reference lab of the Centre Muraz, Bobo-Dioulasso, 141 (59%) were positive. Further characterization of 72 samples has identified three dengue virus serotypes: DENV-2 (58 positives), DENV-3 (12 positives) and DENV-1 (2 positives). Cases are currently reported in all the 13 health regions of the country, with 60.8% of cases reported in the central region, particularly in the city of Ouagadougou.
This outbreak is occurring in the context of an improved but still limited dengue surveillance system in Burkina Faso. The weekly case incidence has been on the rise since the detection of the outbreak in week 31 and is likely underestimated. The epidemic has already spread to twelve of the country's thirteen health zones and many public health facilities do not have access to dengue fever diagnostics (RDTs).
Burkina Faso experienced an outbreak of dengue in 2016 which was caused by DENV-2. In the current outbreak, three serotypes were identified: DENV-1, DENV-2, and DENV-3. This could lead to the occurrence of more severe cases, which may not be captured by the surveillance system due to under-reporting from private clinics and healthcare centers in peripheral districts.
The existence of multiple mosquito breeding sites after the rainy season may favor the continued presence of mosquito populations in the affected communities In particular, the peripheral districts of cities in Burkina Faso are characterized by poor sanitation and the accumulation of rubbish dump sites, tires and used containers which provide productive breeding sites for Aedes aegypti mosquitoes (the primary vector for dengue).
WHO recommends adequate and timely case management dengue cases. Surveillance should be strengthened within all affected health zones. Key public health communication messages should be provided. Integrated Vector Management (IVM) activities should be enhanced to remove potential breeding sites, reduce vector populations and minimize individual exposures. This should include both vector control strategies (i.e. environmental management, and chemical and biological control measures), as well as strategies to protect individuals and households. For further information, see:
WHO recommends that countries should consider the introduction of the dengue vaccine CYD-TDV only in geographic settings (national or subnational) where epidemiological data indicate a high burden of disease. Complete recommendations may be found in the WHO position paper on dengue vaccines:
WHO advises against any restriction on travel and trade to Burkina Faso or the affected district based on the available information.
CORRIGENDUM: Updates were made to the numbers and text in the first 3 paragraphs.


CSV files can be edited with numerous programs such as Excel, other sheet editors, or even just a regular text editor.
The slides CSV is broken up into 4 columns of data. These columns are the date, the day name, the slide background color, and the slide text color.
An example row for an A Day is 2018-05-21,A
(the comma indicates the separation of columns in spreadsheet editors like Excel).
All dates are written in the YYYY-MM-DD format, and A or B days only need to be written as a single capital letter (not "A Day")
with no colors specified (since they are automatically selected).
An example row for a custom day could look like 2018-06-19,Regents Testing,pink,black
.
This would make a slide that says "Regents Testing" with black text on a pink background.
Please be sure every week is a group of 5 rows (for Mon-Fri), write "No School" for the day name if there's no school on a weekday.
The first row must start on a Monday.
Once you finish editing your slides .csv file, simply select it in Calendar Upload section, and the process will begin automatically.
It can take some time and the page may freeze depending on how powerful the computer you are on is. All the image processing is done right here in the browser.
The progress bar on the bottom will track the status on the slide generation,
and then when it is complete a .zip file will be automatically downloaded containing all the slides.


FROM MARK AND ROSE KUNTA UNITED NATION ASSYLUM CAMP ABIDJAN WEST AFRICA PHONE:+22508163020<EMAIL_ADDRESS>Dear,
After going through your profile,I became interested in disclosing everything about ourself to you.we are interested in long term relationship.we are the children of late Cheif Vincent Kunta ,A produce merchant of Sierra Leone, who was assassinated by the RUF rebels on the 16 of April 2004.
Unfortunately my mother died for hypertension three week later here in Abidjan and before then my mother has already advised me to look for a person abroad who will assist me by fronting as the foreign partner to our father on whose behalf he deposited the sum of $17.5 Million
This money was deposited with a bank herein Abidjan,it was deposited for a foreign business with his partners. Now that we are in Abidjan and verified the deposit, we need your assistance to help me to transfer this money out,for investment in your country.
we ask you to scout for a valuable and lucrative business so that both of us can invest wisely, apart from the relationship. we have in mind to give you 20% of the total and 5% for any expenses which you may incure in course of this transaction.
By this mail you are now requested to arrange on how this money will be transfer into your account by sending your details information like telephone and fax number with your bank information deatils so that the transfer will be faster.
Waiting for your quick<EMAIL_ADDRESS>Yours sincerely Mark and Rose Kunta


Error #23: READ ERROR (checksum error in data block),TT,SS This error message indicates that there is an error in one or more of the data bytes. The data has been read into the DOS memory, but the checksum over the data is in error. This message may also indicate grounding problems.


{% extends 'layout.html' %} {% block main_content %} {% if current_user.is_anonymous %}
You are not logged in, so you can't add a new kingdom. Try logging in first