Rangers decline ‘20 options for new catcher, 2 relievers
ARLINGTON, Texas (AP) - The Texas Rangers have declined 2020 contract options for relievers Shawn Kelley and Nate Jones, and newly acquired catcher Welington Castillo. They all became free agents.
Texas announced the moves Friday, a day after acquiring Castillo in a trade from the Chicago White Sox.
Castillo has an $8 million option and a $500,000 buyout. The 32-year-old catcher hit .209 over 72 games last season.
Kelley was 5-2 with 11 saves and a 4.94 ERA in 50 games, with two stints on the injured list. The 35-year-old Kelley had a $2.5 million option with a $250,000 buyout.
Jones, who has a $3.75 million club option with a $1.25 million buyout, was acquired in July from the White Sox while recovering from right forearm surgery. He had a 3.48 ERA in 13 relief appearances in Chicago before going on the injury list in April.
More AP MLB: https://apnews.com/MLB and https://twitter.com/AP_Sports
Sign up for Daily Newsletters
Copyright © 2019 The Washington Times, LLC.
Please read our comment policy before commenting.


Nucleator CLI Reference
nucleator-bakery(1) Manual Page
NAME
nucleator-bakery - Provision, Configure and Publish Operations on EC2 Amazon Machine Images
SYNOPSIS
nucleator bakery provision <args> [options] nucleator bakery configure <args> [options] nucleator bakery publish <args> [options] nucleator bakery delete <args> [options]
DESCRIPTION
The bakery command and its subcommands are used to create and publish Amazon Machine Images.
Running nucleator bakery provision and nucleator bakery configure multiple times is safe, because provisioning and configuration operations are idempotent. If no changes have been made to the stackset definition in ~/.nucleator/contrib/bakery, these commands will result in no change. If updates were made to to the Stackset definition (via nucleator update, for example) that are consistent with CloudFormation’s "update in place" capabilities, the stackset will be updated in place so that AWS resources are brought into alignment with the new stackset definition. This can be useful, for example, when modifying security groups to support application communication on various ports that the app may require.
The bakery command provides the ability to easily create an EC2 instance from an Amazon Machine Image (AMI), make the instance available for further configuration and then create (bake) a new AMI based on that instance via the Nucleator CLI.
SUBCOMMANDS
BAKERY PROVISION
- nucleator bakery provision
-
--customer <customer_name> --group <bakery_ansible_role> [--cage <cage_name>] [--ami-id <id> [--ami-name <name>] [--name <instance_name>] [--keypair-name <keypair_name>]
nucleator bakery provision creates an AWS EC2 instance in the specified cage for the specified customer. Either an ID or a name must be provided for the source AMI from which the EC2 instance will be launched. One of the two options must be provided. If you expect to login to the instance, you should provide a keypair name. If you don’t specify a cage name, it will use the build cage. If you don’t specify a name for the instance, it will use singleton.
The group option lets you specify a set of Ansible roles which will be used during the provisioning, configuring and published steps. These roles will go by the names "<group>_provision", "<group>_configure", "<group>_publish", "<group>_templates". Examples of these are provided for both Linux and Windows instances in this GitHub repo. Those roles should be copied into your Nucleator installation directory: ~/.nucleator/contrib/bakery-roles/ansible/roles/example_linux_provision for example.
BAKERY CONFIGURE
- nucleator bakery configure
-
--customer <customer_name> --group <bakery_ansible_role> [--cage <cage_name>] [--name <bakery_instance_name>] [-h | --help]
nucleator bakery configure performs post-provisioning configuration of the EC2 instance associated with the bakery.
BAKERY PUBLISH
- nucleator bakery publish
-
--customer <customer_name> --group <bakery_ansible_role> --ami-name <ami__name> [--cage <cage_name>] [--name <bakery_instance_name>] [--ami-region <region>]
nucleator bakery publish creates the AMI from the named EC2 instance. The ami-name is applied to that AMI which is published into the specified region. If no region is specified, it will go into the same region as where the EC2 instance is running.
BAKERY DELETE
- nucleator bakery delete
-
--customer <customer_name> --group <bakery_ansible_role> --cage <cage_name> --name <bakery_instance_name>
nucleator bakery delete deletes the bakery instance specified by <bakery_application_name> from the specified Nucleator cage.
OPTIONS
- --customer <customer_name>
-
The name of the customer for whom the specified cage was provisioned.
- --cage <cage_name>
-
The name of the cage in which to provision and maintain the bakery. When this option is not required, the default is build.
- --group <group_name>
-
The name of a set if Ansible roles which will be used to provide custom provisioning and configuration. These roles, written by the customer, will go by the names "<group>_provision", "<group>_configure", "<group>_publish", "<group>_templates". Examples of these are provided for both Linux and Windows instances in this GitHub repo. Those roles should be copied into your Nucleator installation directory: ~/.nucleator/contrib/bakery-roles/ansible/roles/example_linux_provision for example.
- --ami-id <id>
-
The ID of an Amazon Machine Image (AMI) which will be the source of the EC2 instance which will be launched. This AMI needs to reside in the region of the cage which you have specified. When this option is not required, it means that Nucelator will look for an AMI with the name specified by the next option, "ami-name".
- --ami-name <name>
-
The name of an Amazon Machine Image (AMI) which will be the source of the EC2 instance which will be launched. This AMI needs to reside in the region of the cage which you have specified. When this option is not required, it means that Nucelator will look for an AMI with the ID specified by the previous option, "ami-id". For the publish command, this value will be assigned to the resultant AMI.
- --name <instance_name>
-
The "instance_name" value will be assigned to the launched EC2 instance. If this option is not specified, a default value of singleton is used.
- --keypair-name <keypair_name>
-
If you will need to login to the launched EC2 instance, the keypair should be specified so that it can be associated with the EC2 instance at launch time.
- --ami-region <region_name>
-
The publish command will place the resulting AMI in the specified region. If not specified, the AMI will be published in the region where the EC2 instance is running.
- -h
- --help
-
Show help for this command.
FILES
- NUCLEATOR_INSTALL_DIR/nucleator-core/lib/nucleator/core/foundation/ansible/roles/config/vars/aws_service_config.yml
-
AWS Services config file including dicts for currently supported EC2 and RDS instance types.
- ~/.nucleator/contrib/bakery/ansible/roles/bakery_provision/defaults/main.yml
-
Default values for optional arguments to the bakery command.
- ~/.nucleator/contrib/bakery-roles/ansible/roles
-
The customer-provided Ansible roles should be placed in this directory.
NUCLEATOR
Part of the nucleator(1) suite


A responsive site will always fit your device's screen. The layout of the site will adjust automatically. It will provide an optimal viewing experience with end-user across a wide range of devices.
Mobile first design means what it says. This is a user experience consideration that must be made at design time. It is important because more and more users using mobile as their first choice to visit website. A research found 25% of U.S user are mobile only, and up to 45% of Rural China internet user are mobile only in 2013. This number will continue growing as time goes.
| Pros | Cons |
|---|---|
| Development quick and easy | Restricts your freedom |
| Well- tested code | Only learned framework not language |
| Support | Code is public |
A wireframe is sketch of your webpage layout. The wireframe used as a basic structure of webpage. It will guide you when you in the development stage. An example below will show how I using wireframe to develop my Blog.
I built this website with Skelton framework. I think everything was good with this small framework. The only downside is the library is too small. I don’t find the code which I need. I still wrote 145 lines my own CSS.


Elixir v1.3.4 GenEvent behaviour
A behaviour module for implementing event handling functionality.
The event handling model consists of a generic event manager process with an arbitrary number of event handlers which are added and deleted dynamically.
An event manager implemented using this module will have a standard set of interface functions and include functionality for tracing and error reporting. It will also fit into a supervision tree.
Example
There are many use cases for event handlers. For example, a logging system can be built using event handlers where each log message is an event and different event handlers can be attached to handle the log messages. One handler may print error messages on the terminal, another can write it to a file, while a third one can keep the messages in memory (like a buffer) until they are read.
As an example, let’s have a GenEvent that accumulates messages until they are collected by an explicit call.
# Define an Event Handler
defmodule LoggerHandler do
use GenEvent
# Callbacks
def handle_event({:log, x}, messages) do
{:ok, [x | messages]}
end
def handle_call(:messages, messages) do
{:ok, Enum.reverse(messages), []}
end
end
# Start a new event manager.
{:ok, pid} = GenEvent.start_link([])
# Attach an event handler to the event manager.
GenEvent.add_handler(pid, LoggerHandler, [])
#=> :ok
# Send some events to the event manager.
GenEvent.notify(pid, {:log, 1})
#=> :ok
GenEvent.notify(pid, {:log, 2})
#=> :ok
# Call functions on specific handlers in the manager.
GenEvent.call(pid, LoggerHandler, :messages)
#=> [1, 2]
GenEvent.call(pid, LoggerHandler, :messages)
#=> []
We start a new event manager by calling GenEvent.start_link/1
.
Notifications can be sent to the event manager which will then
invoke handle_event/2
for each registered handler.
We can add new handlers with add_handler/3
and add_mon_handler/3
.
Calls can also be made to specific handlers by using call/3
.
Callbacks
There are 6 callbacks required to be implemented in a GenEvent
. By
adding use GenEvent
to your module, Elixir will automatically define
all 6 callbacks for you, leaving it up to you to implement the ones
you want to customize.
Name Registration
A GenEvent is bound to the same name registration rules as a GenServer
.
Read more about it in the GenServer
docs.
Modes
GenEvent supports three different notifications.
On GenEvent.ack_notify/2
, the manager acknowledges each event,
providing backpressure, but processing of the message happens
asynchronously.
On GenEvent.sync_notify/2
, the manager acknowledges an event
just after it is processed by all event handlers.
On GenEvent.notify/2
, all events are processed asynchronously and
there is no ack (which means there is no backpressure).
Streaming
GenEvent
messages can be streamed with the help of stream/2
.
You will need to start another process to consume the stream:
Task.start_link fn ->
stream = GenEvent.stream(pid)
# Discard the next 3 events
_ = Enum.take(stream, 3)
# Print all remaining events
for event <- stream do
IO.inspect event
end
end
Now call GenEvent.notify/2
multiple times. You will see the
first three events will be skipped while the rest will be
continuously printed.
Learn more and compatibility
If you wish to find out more about GenEvent, the documentation and links in Erlang can provide extra insight.
Keep in mind though Elixir and Erlang gen events are not 100% compatible.
The :gen_event.add_sup_handler/3
is not supported by Elixir’s GenEvent,
which in turn supports GenEvent.add_mon_handler/3
.
The benefits of the monitoring approach are described in the “Don’t drink too much kool aid” section of the “Learn you some Erlang” link above. Due to those changes, Elixir’s GenEvent does not trap exits by default.
Furthermore, Elixir also normalizes the {:error, _}
tuples returned
by many functions, in order to be more consistent with themselves and
the GenServer
module.
Summary
Types
Supported values for new handlers
The event manager reference
The GenEvent manager name
Return values of start*
functions
Options used by the start*
functions
Functions
Sends an ack event notification to the event manager
Adds a new event handler to the event manager
Adds a monitored event handler to the event manager
Makes a synchronous call to the event handler
installed in manager
Sends an event notification to the event manager
Removes an event handler from the event manager
Starts an event manager process without links (outside of a supervision tree)
Starts an event manager linked to the current process
Stops the manager with the given reason
Returns a stream that consumes events from the manager
Replaces an old event handler with a new one in the event manager
Replaces an old event handler with a new monitored one in the event manager
Sends a sync event notification to the event manager
Returns a list of all event handlers installed in the manager
Callbacks
Invoked to change the state of the handler when a different version of the handler’s module is loaded (hot code swapping) and the state’s term structure should be changed
Invoked to handle synchronous call/4
messages to a specific handler
Invoked to handle notify/2
, ack_notify/2
or sync_notify/2
messages
Invoked to handle all other messages. All handlers are run in the GenEvent
process so messages intended for other handlers should be ignored with a catch
all clause
Invoked when the handler is added to the GenEvent
process. add_handler/3
(and add_mon_handler/3
will block until it returns
Invoked when the server is about to exit. It should do any cleanup required
Types
Supported values for new handlers
The GenEvent manager name
Return values of start*
functions
Functions
Sends an ack event notification to the event manager
.
In other words, this function only returns :ok
as soon as the
event manager starts processing this event, but it does not wait
for event handlers to process the sent event.
See notify/2
for more info. Note this function is specific
to Elixir’s GenEvent and does not work with Erlang ones.
Adds a new event handler to the event manager
.
The event manager will call the init/1
callback with args
to
initiate the event handler and its internal state.
If init/1
returns a correct value indicating successful completion,
the event manager adds the event handler and this function returns
:ok
. If the callback fails with reason
or returns {:error, reason}
,
the event handler is ignored and this function returns {:error, reason}
.
If the given handler was previously installed at the manager, this
function returns {:error, :already_present}
.
For installing multiple instances of the same handler, {Module, id}
instead
of Module
must be used. The handler could be then referenced with
{Module, id}
instead of just Module
.
Adds a monitored event handler to the event manager
.
Expects the same input and returns the same values as add_handler/3
.
Monitored handlers
A monitored handler implies the calling process will now be monitored by the GenEvent manager.
If the calling process later terminates with reason
, the event manager
will delete the event handler by calling the terminate/2
callback with
{:stop, reason}
as argument. If the event handler later is deleted,
the event manager sends a message {:gen_event_EXIT, handler, reason}
to the calling process. Reason is one of the following:
:normal
- if the event handler has been removed due to a call toremove_handler/3
, or:remove_handler
has been returned by a callback function:shutdown
- if the event handler has been removed because the event manager is terminating{:swapped, new_handler, pid}
- if the process pid has replaced the event handler by anotherterm
- if the event handler is removed due to an error. Which term depends on the error
Keep in mind that the {:gen_event_EXIT, handler, reason}
message is not
guaranteed to be delivered in case the manager crashes. If you want to
guarantee the message is delivered, you have two options:
- monitor the event manager
- link to the event manager and then set
Process.flag(:trap_exit, true)
in your handler callback
Finally, this functionality only works with GenEvent started via this
module (it is not backwards compatible with Erlang’s :gen_event
).
Makes a synchronous call to the event handler
installed in manager
.
The given request
is sent and the caller waits until a reply arrives or
a timeout occurs. The event manager will call handle_call/2
to handle
the request.
The return value reply
is defined in the return value of handle_call/2
.
If the specified event handler is not installed, the function returns
{:error, :not_found}
.
Sends an event notification to the event manager
.
The event manager will call handle_event/2
for each
installed event handler.
notify
is asynchronous and will return immediately after the
notification is sent. notify
will not fail even if the specified
event manager does not exist, unless it is specified as an atom.
Removes an event handler from the event manager
.
The event manager will call terminate/2
to terminate the event handler
and return the callback value. If the specified event handler is not
installed, the function returns {:error, :not_found}
.
Starts an event manager process without links (outside of a supervision tree).
See start_link/1
for more information.
Starts an event manager linked to the current process.
This is often used to start the GenEvent
as part of a supervision tree.
It accepts the :name
option which is described under the Name Registration
section in the GenServer
module docs.
If the event manager is successfully created and initialized, the function
returns {:ok, pid}
, where pid is the pid of the server. If a process with
the specified server name already exists, the function returns
{:error, {:already_started, pid}}
with the pid of that process.
Note that a GenEvent
started with start_link/1
is linked to the
parent process and will exit not only on crashes but also if the parent
process exits with :normal
reason.
stop(manager, reason :: term, timeout) :: :ok
Stops the manager with the given reason
.
Before terminating, the event manager will call
terminate(:stop, ...)
for each installed event handler.
It returns :ok
if the manager terminates with the given
reason, if it terminates with another reason, the call will
exit.
This function keeps OTP semantics regarding error reporting.
If the reason is any other than :normal
, :shutdown
or
{:shutdown, _}
, an error report will be logged.
Returns a stream that consumes events from the manager
.
The stream is a GenEvent
struct that implements the Enumerable
protocol. Consumption of events only begins when enumeration starts.
Note streaming is specific to Elixir’s GenEvent and does not work with Erlang ones.
Options
:timeout
- raises if no event arrives in X milliseconds (defaults to:infinity
)
Replaces an old event handler with a new one in the event manager
.
First, the old event handler is deleted by calling terminate/2
with
the given args1
and collects the return value. Then the new event handler
is added and initiated by calling init({args2, term})
, where term
is the
return value of calling terminate/2
in the old handler. This makes it
possible to transfer information from one handler to another.
The new handler will be added even if the specified old event handler
is not installed or if the handler fails to terminate with a given reason
in which case state = {:error, term}
.
If init/1
in the second handler returns a correct value, this
function returns :ok
.
Replaces an old event handler with a new monitored one in the event manager
.
Read the docs for add_mon_handler/3
and swap_handler/5
for more information.
Sends a sync event notification to the event manager
.
In other words, this function only returns :ok
after the event manager
invokes the handle_event/2
callback on each installed event handler.
See notify/2
for more info.
Callbacks
code_change(old_vsn, state :: term, extra :: term) :: {:ok, new_state :: term} when old_vsn: term | {:down, term}
Invoked to change the state of the handler when a different version of the handler’s module is loaded (hot code swapping) and the state’s term structure should be changed.
old_vsn
is the previous version of the module (defined by the @vsn
attribute) when upgrading. When downgrading the previous version is wrapped in
a 2-tuple with first element :down
. state
is the current state of the
handler and extra
is any extra data required to change the state.
Returning {:ok, new_state}
changes the state to new_state
and the code
change is successful.
If code_change/3
raises, the code change fails and the handler will continue
with its previous state. Therefore this callback does not usually contain side
effects.
handle_call(request :: term, state :: term) :: {:ok, reply, new_state} | {:ok, reply, new_state, :hibernate} | {:remove_handler, reply} when reply: term, new_state: term
Invoked to handle synchronous call/4
messages to a specific handler.
request
is the request message sent by a call/4
and state
is the current
state of the handler.
Returning {:ok, reply, new_state}
sends reply
as a response to the call
and sets the handler’s state to new_state
.
Returning {:ok, reply, new_state, :hibernate}
is similar to
{:ok, reply, new_state}
except the process is hibernated. See
handle_event/2
for more information on hibernation.
Returning {:remove_handler, reply}
sends reply
as a response to the call,
removes the handler from the GenEvent
loop and calls terminate/2
with
reason :remove_handler
and state state
.
handle_event(event :: term, state :: term) :: {:ok, new_state} | {:ok, new_state, :hibernate} | :remove_handler when new_state: term
Invoked to handle notify/2
, ack_notify/2
or sync_notify/2
messages.
event
is the event message and state
is the current state of the handler.
Returning {:ok, new_state}
sets the handler’s state to new_state
and the
GenEvent
loop continues.
Returning {:ok, new_state, :hibernate}
is similar to
{:ok, new_state}
except the process is hibernated once all handlers have
handled the events. The GenEvent
process will continue the loop once a
message is its message queue. If a message is already in the message queue
this will be immediately. Hibernating a GenEvent
causes garbage collection
and leaves a continuous heap that minimises the memory used by the process.
Hibernating should not be used aggressively as too much time could be spent garbage collecting. Normally it should only be used when a message is not expected soon and minimising the memory of the process is shown to be beneficial.
Returning :remove_handler
removes the handler from the GenEvent
loop and
calls terminate/2
with reason :remove_handler
and state state
.
handle_info(msg :: term, state :: term) :: {:ok, new_state} | {:ok, new_state, :hibernate} | :remove_handler when new_state: term
Invoked to handle all other messages. All handlers are run in the GenEvent
process so messages intended for other handlers should be ignored with a catch
all clause.
msg
is the message and state
is the current state of the handler.
Return values are the same as handle_event/2
.
init(args :: term) :: {:ok, state} | {:ok, state, :hibernate} | {:error, reason :: any} when state: any
Invoked when the handler is added to the GenEvent
process. add_handler/3
(and add_mon_handler/3
will block until it returns.
args
is the argument term (third argument) passed to add_handler/3
.
Returning {:ok, state}
will cause add_handler/3
to return :ok
and the
handler to become part of the GenEvent
loop with state state
.
Returning {:ok, state, :hibernate}
is similar to
{:ok, state}
except the GenEvent
process is hibernated before continuing
its loop. See handle_event/2
for more information on hibernation.
Returning {:error, reason}
will cause add_handler/3
to return
{:error, reason}
and the handler is not added to GenEvent
loop.
terminate(reason, state :: term) :: term when reason: :stop | {:stop, term} | :remove_handler | {:error, term} | term
Invoked when the server is about to exit. It should do any cleanup required.
reason
is removal reason and state
is the current state of the handler.
The return value is returned to GenEvent.remove_handler/3
or ignored if
removing for another reason.
reason
is one of:
:stop
- manager is terminating{:stop, term}
- monitored process terminated (for monitored handlers):remove_handler
- handler is being removed{:error, term}
- handler crashed or returned a bad value and an error is loggedterm
- any term passed to functions likeGenEvent.remove_handler/3
If part of a supervision tree, a GenEvent
’s Supervisor
will send an exit
signal when shutting it down. The exit signal is based on the shutdown
strategy in the child’s specification. If it is :brutal_kill
the GenEvent
is killed and so terminate/2
is not called for its handlers. However if it is
a timeout the Supervisor
will send the exit signal :shutdown
and the
GenEvent
will have the duration of the timeout to call terminate/2
on all
of its handlers - if the process is still alive after the timeout it is
killed.
If the GenEvent
receives an exit signal (that is not :normal
) from any
process when it is not trapping exits it will exit abruptly with the same
reason and so not call the handlers’ terminate/2
. Note that a process does
NOT trap exits by default and an exit signal is sent when a linked process
exits or its node is disconnected. Therefore it is not guaranteed that
terminate/2
is called when a GenEvent
exits.
Care should be taken to cleanup because the GenEvent
can continue to loop
after removing the handler. This is different to most other OTP behaviours.
For example if the handler controls a port
(e.g. :gen_tcp.socket
) or
File.io_device
, it will be need to be closed in terminate/2
as the
process is not exiting so will not be automatically cleaned up.


JADE
Copyright (c) 2001 Mark Thompson
Jade is played on an empty hexagonal grid in the shape of a parallelogram with size MxN (both odd numbers and not equal). The size currently considered best is 11x9, but other sizes and shapes could be used. Since my diagram tool cannot draw this type of board, I present an example with size 9x9 (use your imagination to add two extra rows at one edge for a real game).
- TURN - On each turn, each player drops a white or black stone on an empty cell.
- One player is called Cross and the other is called Parallel. Cross starts the game.
- GOAL - Each player has a different goal:
- Cross wins if a group of either color is formed that connects all four edges
- Parallel wins if either pair of opposite edges is joined by "parallel" chains of both colors.
An example Cross just played the marked white stone and with this move, he wins the match.
If Parallel drops a white stone at cell [1], Cross will win using the white structure. If Parallel drops a black stone at cell [1], Cross will win using the black structure.
Jade can be played on Richard's PbM server. Some words from the author: Draws are impossible. Proof: Note that draws are impossible in conventional Hex, because when a board is filled either Black will connect the two Black edges or White the two White edges. So I claim that when a board is filled, either Parallel or Cross will have won a game of Jade. For if you color the edges as a Hex game, either Black or White will have won that Hex game; and if you then recolor the edges in the opposite colors, again either Black or White will have won this second Hex game. If the two Hex games are won by the same player, then Parallel has won the Jade game; if by different players, then Cross has won the Jade game. Q.E.D.


Endless Plains [ai77], plain, in Imperia, peasants: 134
Last updated Turn #118
Endless Plains [ai77], plain, in Imperia, peasants: 134
------------------------------------------------------------------------
12: Pleasure Sloop [v5n], ship, 30 hulls, 1 rowing port, 90 sails, arrived
12: from Ocean [ah77], owner:
12: Dorothy [v1b], Pen, with 39 peasants, 30 soldiers, 94 sailors,
12: accompanied by:
12: Cindy [z1c], Pen, with seven peasants, one worker, 40 soldiers,
12: nine skirmishers
12: Banian [e7n], Imperial Empire, knight, the High Priest of the
12: Church of Eres [151], with 16 soldiers, ten angels
12: Drummond [x8q], Imperial Empire, with 30 soldiers
12: Roland [o6t], Imperial Empire, Bishop of the Church of
12: Anteus [152], with 34 soldiers, five angels
12: Fortuis [h1m], Imperial Empire, with 20 soldiers
13: Pleasure Sloop [v5n], ship, 30 hulls, 1 rowing port, 90 sails,
13: departed for Ocean [aj77].
19: Stack of nazgul [gp6d], nazgul, arrived from the west.
21: Stack of nazgul [gp6d], nazgul, went east.
24: Stack of nazgul [fq3z], nazgul, number: 2, arrived from the west.
26: Stack of nazgul [fq3z], nazgul, number: 2, went east.
29: Stack of nazgul [gp6d], nazgul, arrived from the east.
30: The population grows by one peasant.
Routes leaving Endless Plains:
North, to Ocean [ah77], Crystal Sea, 2 days
East, plain, to Endless Plains [ai78], 7 days
South, to Ocean [aj77], Crystal Sea, 2 days
West, plain, to Endless Plains [ai76], 7 days
Inner locations:
Rocky hill [ad2b], rocky hill, 1 day, owner:
Ratspider [hp5d], ratspiders, number: 51
Rocky hill [ad2c], rocky hill, 1 day, owner:
Chimera [is5z], chimera, number: 2
Seen here:
Stack of nazgul [it6z], nazgul, number: 3
Stack of nazgul [gp6d], nazgul


Introduction
Neo4j 3.0 introduced the concept of user defined procedures. Those are custom implementations of certain functionality, that can’t be (easily) expressed in Cypher itself. Those procedures are implemented in Java and can be easily deployed into your Neo4j instance, and then be called from Cypher directly.
The APOC library consists of many (about 300) procedures to help with many different tasks in areas like data integration, graph algorithms or data conversion.
License
Apache License 2.0
"APOC" Name history
Apoc was the technician and driver on board of the Nebuchadnezzar in the Matrix movie. He was killed by Cypher.
APOC was also the first bundled A Package Of Components for Neo4j in 2009.
APOC also stands for "Awesome Procedures On Cypher"
Installation
Download latest release
Go to http://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/<IP_ADDRESS>
to find the latest release and download the binary jar to place into your $NEO4J_HOME/plugins
folder.
Version Compatibility Matrix
Since APOC relies in some places on Neo4j’s internal APIs you need to use the right APOC version for your Neo4j installaton.
Any version to be released after 1.1.0 will use a different, consistent versioning scheme: <neo4j-version>.<apoc>
version. The trailing <apoc>
part of the version number will be incremented with every apoc release.
apoc version |
neo4j version |
<IP_ADDRESS> |
3.1.0 (3.1.x) |
<IP_ADDRESS> |
3.0.8 (3.0.x) |
<IP_ADDRESS> |
3.0.4 (3.0.x) |
1.1.0 |
3.0.0 - 3.0.3 |
1.0.0 |
3.0.0 - 3.0.3 |
using APOC with Neo4j Docker image
The Neo4j Docker image allows to supply a volume for the /plugins
folder. Download the APOC release fitting your Neo4j version to local folder plugins
and provide it as a data volume:
mkdir plugins
pushd plugins
wget https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/<IP_ADDRESS>/apoc-<IP_ADDRESS>-extended.jar
popd
docker run --rm -e NEO4J_AUTH=none -p 7474:7474 -v $PWD/plugins:/plugins -p 7687:7687 neo4j:3.1.2
Build & install the current development branch from source
git clone http://github.com/neo4j-contrib/neo4j-apoc-procedures ./gradlew shadow cp build/libs/apoc-<version>-SNAPSHOT-extended.jar $NEO4J_HOME/plugins/ $NEO4J_HOME/bin/neo4j restart
A full build including running the tests can be run by ./gradlew build
.
Calling Procedures & Functions within Cypher
User defined Functions can be used in any expression or predicate, just like built-in functions.
Procedures can be called stand-alone with CALL procedure.name();
But you can also integrate them into your Cypher statements which makes them so much more powerful.
WITH 'https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/master/src/test/resources/person.json' AS url
CALL apoc.load.json(url) YIELD value as person
MERGE (p:Person {name:person.name})
ON CREATE SET p.age = person.age, p.children = size(person.children)
Configuration Options
Set these config options in $NEO4J_HOME/neo4j.conf
All boolean options default to false, i.e. they are disabled, unless mentioned otherwise.
|
Enable triggers |
|
Enable time to live background task |
|
Set frequency in seconds to run ttl background task (default 60) |
|
Enable reading local files from disk |
|
Enable writing local files to disk |
|
store jdbc-urls under a key to be used by apoc.load.jdbc |
|
store es-urls under a key to be used by elasticsearch procedures |
|
store mongodb-urls under a key to be used by mongodb procedures |
|
store couchbase-urls under a key to be used by couchbase procedures |
Manual Indexes
Index Queries
Procedures to add to and query manual indexes
|
Note
|
Please note that there are (case-sensitive) automatic schema indexes, for equality, non-equality, existence, range queries, starts with, ends-with and contains! |
|
add all nodes to this full text index with the given fields, additionally populates a 'search' index field with all of them in one place |
|
add node to an index for each label it has |
|
add node to an index for the given label |
|
add node to an index for the given name |
|
add relationship to an index for its type |
|
add relationship to an index for the given name |
|
apoc.index.removeRelationshipByName('name',rel) remove relationship from an index for the given name |
|
search for the first 100 nodes in the given full text index matching the given lucene query returned by relevance |
|
lucene query on node index with the given label name |
|
lucene query on relationship index with the given type name |
|
lucene query on relationship index with the given type name bound by either or both sides (each node parameter can be null) |
|
lucene query on relationship index with the given type name for outgoing relationship of the given node, returns end-nodes |
|
lucene query on relationship index with the given type name for incoming relationship of the given node, returns start-nodes |
Index Management
|
lists all manual indexes |
|
removes manual indexes |
|
gets or creates manual node index |
|
gets or creates manual relationship index |
match (p:Person) call apoc.index.addNode(p,["name","age"]) RETURN count(*);
// 129s for 1M People
call apoc.index.nodes('Person','name:name100*') YIELD node, weight return * limit 2
Schema Index Queries
Schema Index lookups that keep order and can apply limits
|
schema range scan which keeps index order and adds limit, values can be null, boundaries are inclusive |
|
schema string search which keeps index order and adds limit, operator is 'STARTS WITH' or 'CONTAINS' |
Loading Data from RDBMS
|
load from relational database, either a full table or a sql statement |
|
load from relational database, either a full table or a sql statement |
|
register JDBC driver of source database |
To simplify the JDBC URL syntax and protect credentials, you can configure aliases in conf/neo4j.conf
:
apoc.jdbc.myDB.url=jdbc:derby:derbyDB
CALL apoc.load.jdbc('jdbc:derby:derbyDB','PERSON') becomes CALL apoc.load.jdbc('myDB','PERSON')
The 3rd value in the apoc.jdbc.<alias>.url=
effectively defines an alias to be used in apoc.load.jdbc('<alias>',….
Loading Data from Web-APIs (JSON, XML, CSV)
|
load from JSON URL (e.g. web-api) to import JSON as stream of values if the JSON was an array or a single value if it was a map |
|
load from XML URL (e.g. web-api) to import XML as single nested map with attributes and |
|
load CSV fom URL as stream of values |
Interacting with Elastic Search
|
elastic search statistics |
|
perform a GET operation |
|
perform a SEARCH operation |
|
perform a raw GET operation |
|
perform a raw POST operation |
|
perform a POST operation |
|
perform a PUT operation |
Interacting with Couchbase
|
Retrieves a couchbase json document by its unique ID |
|
Check whether a couchbase json document with the given ID does exist |
|
Insert a couchbase json document with its unique ID |
|
Insert or overwrite a couchbase json document with its unique ID |
|
Append a couchbase json document to an existing one |
|
Prepend a couchbase json document to an existing one |
|
Remove the couchbase json document identified by its unique ID |
|
Replace the content of the couchbase json document identified by its unique ID. |
|
Executes a plain un-parameterized N1QL statement. |
|
Executes a N1QL statement with positional parameters. |
|
Executes a N1QL statement with named parameters. |
Copy these jars into the plugins directory:
mvn dependency:copy-dependencies cp target/dependency/java-client-2.3.1.jar target/dependency/core-io-1.3.1.jar target/dependency/rxjava-1.1.5.jar $NEO4J_HOME/plugins/
CALL apoc.couchbase.get(['localhost'], 'default', 'artist:vincent_van_gogh')
Streaming Data to Gephi
|
streams provided data to Gephi |
Notes
Gephi has a streaming plugin, that can provide and accept JSON-graph-data in a streaming fashion.
Make sure to install the plugin firsrt and activate it for your workspace (there is a new "Streaming"-tab besides "Layout"), right-click "Master"→"start" to start the server.
You can provide your workspace name (you might want to rename it before you start thes streaming), otherwise it defaults to workspace0
The default Gephi-URL is http://localhost:8080, resulting in http://localhost:8080/workspace0?operation=updateGraph
You can also configure it in conf/neo4j.conf
via apoc.gephi.url=url
or apoc.gephi.<key>.url=url
Example
match path = (:Person)-[:ACTED_IN]->(:Movie)
WITH path LIMIT 1000
with collect(path) as paths
call apoc.gephi.add(null,'workspace0', paths) yield nodes, relationships, time
return nodes, relationships, time
Generating Graphs
Generate undirected (random direction) graphs with semi-real random distributions based on theoretical models.
|
generates a graph according to Erdos-Renyi model (uniform) |
|
generates a graph according to Watts-Strogatz model (clusters) |
|
generates a graph according to Barabasi-Albert model (preferential attachment) |
|
generates a complete graph (all nodes connected to all other nodes) |
|
generates a graph with the given degree distribution |
Example
CALL apoc.generate.ba(1000, 2, 'TestLabel', 'TEST_REL_TYPE')
CALL apoc.generate.ws(1000, null, null, null)
CALL apoc.generate.simple([2,2,2,2], null, null)
Monitoring
(thanks @ikwattro)
|
node and relationships-ids in total and in use |
|
store information such as kernel version, start time, read-only, database-name, store-log-version etc. |
|
store size information for the different types of stores |
|
number of transactions total,opened,committed,concurrent,rolled-back,last-tx-id |
|
db locking information such as avertedDeadLocks, lockCount, contendedLockCount and contendedLocks etc. (enterprise) |
Cypher Execution
|
runs each statement in the file, all semicolon separated - currently no schema operations |
|
executes fragment in parallel batches with the list segments being assigned to _ |
Triggers
Enable apoc.trigger.enabled=true
in $NEO4J_HOME/config/neo4j.conf
first.
Helper Functions
|
function to filter labelEntries by label, to be used within a trigger statement with {assignedLabels} and {removedLabels} {phase:'before/after/rollback'} returns previous and new trigger information |
|
function to filter propertyEntries by property-key, to be used within a trigger statement with {assignedNode/RelationshipProperties} and {removedNode/RelationshipProperties}. Returns [{old,new,key,node,relationship}] |
Helpers
Static Value Storage
|
returns statically stored value from config (apoc.static.<key>) or server lifetime storage |
|
returns statically stored values from config (apoc.static.<prefix>) or server lifetime storage |
|
stores value under key for server livetime storage, returns previously stored or configured value |
Lookup Functions
|
id |
|
quickly returns all nodes with these id’s |
|
id |
|
quickly returns all relationships with these id’s |
Utilities
|
computes the sha1 of the concatenation of all string values of the list |
|
computes the md5 of the concatenation of all string values of the list |
|
sleeps for <duration> millis, transaction termination is honored |
|
raises exception if prediate evaluates to true |
Config
|
Lists the Neo4j configuration as key,value table |
|
Lists the Neo4j configuration as map |
Time to Live (TTL)
Enable TTL with setting in neo4j.conf
: apoc.ttl.enabled=true
There are some convenience procedures to expire nodes.
You can also do it yourself by running
SET n:TTL
SET n.ttl = timestamp() + 3600
Optionally set apoc.ttl.schedule=5
as repeat frequency.
Relationship Filter
Syntax: [<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…
| input | type | direction |
|---|---|---|
|
|
Table of Contents
OUTGOING |
|
|
Table of Contents
INCOMING |
|
|
Table of Contents
BOTH |
Label Filter
Syntax: [+-/]LABEL1|LABEL2|…
| input | label | result |
|---|---|---|
|
|
Table of Contents
include label (whitelist) |
|
|
Table of Contents
exclude label (blacklist) |
|
|
Table of Contents
stop traversal after reaching a friend (but include him) |
Uniqueness
Uniqueness of nodes and relationships guides the expansion and the returned results.
Uniqueness is only configurable using expandConfig()
.
subgraphNodes()
, subgraphAll()
, and spanningTree()
all use 'NODE_GLOBAL' uniqueness.
| value | description |
|---|---|
|
Table of Contents
For each returned node there’s a (relationship wise) unique path from the start node to it. This is Cypher’s default expansion mode. |
|
Table of Contents
A node cannot be traversed more than once. This is what the legacy traversal framework does. |
|
Table of Contents
Entities on the same level are guaranteed to be unique. |
|
Table of Contents
For each returned node there’s a unique path from the start node to it. |
|
Table of Contents
This is like NODE_GLOBAL, but only guarantees uniqueness among the most recent visited nodes, with a configurable count. Traversing a huge graph is quite memory intensive in that it keeps track of all the nodes it has visited. For huge graphs a traverser can hog all the memory in the JVM, causing OutOfMemoryError. Together with this Uniqueness you can supply a count, which is the number of most recent visited nodes. This can cause a node to be visited more than once, but scales infinitely. |
|
Table of Contents
A relationship cannot be traversed more than once, whereas nodes can. |
|
Table of Contents
Entities on the same level are guaranteed to be unique. |
|
Table of Contents
Same as for NODE_RECENT, but for relationships. |
|
Table of Contents
No restriction (the user will have to manage it) |
User Defined Functions
Introduced in Neo4j 3.1.0-M10
Neo4j 3.1 brings some really neat improvements in Cypher alongside other cool features
If you used or wrote procedures in the past, you most probably came across instances where it felt quite unwieldy to call a procedure just to compute something, convert a value or provide a boolean decision.
For example:
CREATE (v:Value {id:{id}, data:{data}})
WITH v
CALL apoc.date.formatDefault(timestamp(), "ms") YIELD value as created
SET v.created = created
You’d rather write it as a function:
CREATE (v:Value {id:{id}, data:{data}, created: apoc.date.format(timestamp()) })
Now in 3.1 that’s possible, and you can also leave off the "ms"
and use a single function name, because the unit
and format
parameters have a default value.
Functions are more limited than procedures: they can’t execute writes or schema operations and are expected to return a single value, not a stream of values. But this makes it also easier to write and use them.
By having information about their types, the Cypher Compiler can also check for applicability.
The signature of the procedure above changed from:
@Procedure("apoc.date.format")
public Stream<StringResult> formatDefault(@Name("time") long time, @Name("unit") String unit) {
return Stream.of(format(time, unit, DEFAULT_FORMAT));
}
to the much simpler function signature (ignoring the parameter name and value annotations):
@UserFunction("apoc.date.format")
public String format(@Name("time") long time,
@Name(value="unit", defaultValue="ms") String unit,
@Name(value="format", defaultValue=DEFAULT_FORMAT) String format) {
return getFormatter().format(time, unit, format);
}
This can then be called in the manner outlined above.
In our APOC procedure library we already converted about 50 procedures into functions from the following areas:
| package | # of functions | example function | |||||
|---|---|---|---|---|---|---|---|
Table of Contents
date & time conversion |
Table of Contents
3 |
|
|||||
Table of Contents
number conversion |
Table of Contents
Table of Contents
collection and map functions Table of Contents
JSON conversion Table of Contents
string functions Table of Contents
hash functions Table of Contents
2
|
You can list user defined functions with SHOW FUNCTIONS
Text and Lookup Indexes
Index Queries
Procedures to add to and query manual indexes
|
Note
|
Please note that there are (case-sensitive) automatic schema indexes, for equality, non-equality, existence, range queries, starts with, ends-with and contains! |
|
add all nodes to this full text index with the given fields, additionally populates a 'search' index field with all of them in one place |
|
add node to an index for each label it has |
|
add node to an index for the given label |
|
add node to an index for the given name |
|
add relationship to an index for its type |
|
add relationship to an index for the given name |
|
apoc.index.removeRelationshipByName('name',rel) remove relationship from an index for the given name |
|
search for the first 100 nodes in the given full text index matching the given lucene query returned by relevance |
|
lucene query on node index with the given label name |
|
lucene query on relationship index with the given type name |
|
lucene query on relationship index with the given type name bound by either or both sides (each node parameter can be null) |
|
lucene query on relationship index with the given type name for outgoing relationship of the given node, returns end-nodes |
|
lucene query on relationship index with the given type name for incoming relationship of the given node, returns start-nodes |
Index Management
|
lists all manual indexes |
|
removes manual indexes |
|
gets or creates manual node index |
|
gets or creates manual relationship index |
match (p:Person) call apoc.index.addNode(p,["name","age"]) RETURN count(*);
// 129s for 1M People
call apoc.index.nodes('Person','name:name100*') YIELD node, weight return * limit 2
Manual Indexes
Data Used
The below examples use flight data.
Here is a sample subset of the data that can be load to try the procedures:
CREATE (slc:Airport {abbr:'SLC', id:14869, name:'SALT LAKE CITY INTERNATIONAL'})
CREATE (oak:Airport {abbr:'OAK', id:13796, name:'METROPOLITAN OAKLAND INTERNATIONAL'})
CREATE (bur:Airport {abbr:'BUR', id:10800, name:'BOB HOPE'})
CREATE (f2:Flight {flight_num:6147, day:2, month:1, weekday:6, year:2016})
CREATE (f9:Flight {flight_num:6147, day:9, month:1, weekday:6, year:2016})
CREATE (f16:Flight {flight_num:6147, day:16, month:1, weekday:6, year:2016})
CREATE (f23:Flight {flight_num:6147, day:23, month:1, weekday:6, year:2016})
CREATE (f30:Flight {flight_num:6147, day:30, month:1, weekday:6, year:2016})
CREATE (f2)-[:DESTINATION {arr_delay:-13, taxi_time:9}]->(oak)
CREATE (f9)-[:DESTINATION {arr_delay:-8, taxi_time:4}]->(bur)
CREATE (f16)-[:DESTINATION {arr_delay:-30, taxi_time:4}]->(slc)
CREATE (f23)-[:DESTINATION {arr_delay:-21, taxi_time:3}]->(slc)
CREATE (f30)-[:DESTINATION]->(slc)
Using Manual Index on Node Properties
In order to create manual index on a node property, you call apoc.index.addNode
with the node, providing the properties to be indexed.
MATCH (a:Airport)
CALL apoc.index.addNode(a,['name'])
RETURN count(*)
The statement will create the node index with the same name as the Label name(s) of the node in this case Airport
and add the node by their properties to the index.
Once this has been added check if the node index exists using apoc.index.list
.
CALL apoc.index.list()
Usually apoc.index.addNode
would be used as part of node-creation, e.g. during LOAD CSV.
There is also apoc.index.addNodes
for adding a list of multiple nodes at once.
Once the node index is created we can start using it.
Here are some examples:
The apoc.index.nodes
finds nodes in a manual index using the given lucene query.
|
Note
|
That makes only sense if you combine multiple properties in one lookup or use case insensitive or fuzzy matching full-text queries. In all other cases the built in schema indexes should be used. |
CALL apoc.index.nodes('Airport','name:inter*') YIELD node AS airport, weight
RETURN airport.name, weight
LIMIT 10
|
Note
|
Apoc index queries not only return nodes and relationships but also a weight, which is the score returned from the underlying Lucene index. The results are also sorted by that score. That’s especially helpful for partial and fuzzy text searches. |
To remove the node index Airport
created, use:
CALL apoc.index.remove('Airport')
Using Manual Index on Relationship Properties
The procedure apoc.index.addRelationship
is used to create a manual index on relationship properties.
As there are no schema indexes for relationships, these manual indexes can be quite useful.
MATCH (:Flight)-[r:DESTINATION]->(:Airport)
CALL apoc.index.addRelationship(r,['taxi_time'])
RETURN count(*)
The statement will create the relationship index with the same name as relationship-type, in this case DESTINATION
and add the relationship by its properties to the index.
Using apoc.index.relationships
, we can find the relationship of type DESTINATION
with the property taxi_time
of 11 minutes.
We can chose to also return the start and end-node.
CALL apoc.index.relationships('DESTINATION','taxi_time:11') YIELD rel, start AS flight, end AS airport
RETURN flight_num.flight_num, airport.name;
|
Note
|
Manual relationship indexed do not only store the relationship by its properties but also the start- and end-node. |
That’s why we can use that information to subselect relationships not only by property but also by those nodes, which is quite powerful.
With apoc.index.in
we can pin the node with incoming relationships (end-node) to get the start nodes for all the DESTINATION
relationships.
For instance to find all flights arriving in 'SALT LAKE CITY INTERNATIONAL' with a taxi_time of 7 minutes we’d use:
MATCH (a:Airport {name:'SALT LAKE CITY INTERNATIONAL'})
CALL apoc.index.in(a,'DESTINATION','taxi_time:7') YIELD node AS flight
RETURN flight
The opposite is apoc.index.out
, which takes and binds end-nodes and returns start-nodes of relationships.
Really useful to quickly find a subset of relationships between nodes with many relationships (tens of thousands to millions) is apoc.index.between
.
Here you bind both the start and end-node and provide (or not) properties of the relationships.
MATCH (f:Flight {flight_num:6147})
MATCH (a:Airport {name:'SALT LAKE CITY INTERNATIONAL'})
CALL apoc.index.between(f,'DESTINATION',a,'taxi_time:7') YIELD rel, weight
RETURN *
To remove the relationship index DESTINATION
that was created, use.
CALL apoc.index.remove('DESTINATION')
Full Text Search
Indexes are used for finding nodes in the graph that further operations can then continue from. Just like in a book where you look at the index to find a section that interest you, and then start reading from there. A full text index allows you to find occurrences of individual words or phrases across all attributes.
In order to use the full text search feature, we have to first index our data by specifying all the attributes we want to index.
Here we create a full text index called “locations”
(we will use this name when searching in the index) with our data.
Optionally you can enable tracking changes to the graph on a per index level. To do so, you need to take two actions:
-
set
apoc.autoUpdate.enabled=true
in yourneo4j.conf
. With that setting aTransactionEventHandler
is registered upon startup of your graph database that reflects property changes to the respective fulltext index. -
By default index tracking is done synchronously within the same transaction. Optionally this can be done asynchronous by setting
apoc.autoUpdate.async=true
. -
indexing is started with:
CALL apoc.index.addAllNodes('locations',{
Company: ["name", "description"],
Person: ["name","address"],
Address: ["address"]})
Creating the index will take a little while since the procedure has to read through the entire database to create the index.
We can now use this index to search for nodes in the database. The most simple case would be to search across all data for a particular word.
It does not matter which property that word exists in, any node that has that word in any of its indexed properties will be found.
If you use a name in the call, all occurrences will be found (but limited to 100 results).
CALL apoc.index.search("locations", 'name')
Advanced Search
We can further restrict our search to only searching in a particular attribute.
In order to search for a Person
with an address in France, we use the following.
CALL apoc.index.search("locations", "Person.address:France")
Now we can search for nodes with a specific property value, and then explore their neighbourhoods visually.
But integrating it with an graph query is so much more powerful.
Fulltext and Graph Search
We could for instance search for addresses in the database that contain the word "Paris", and then find all companies registered at those addresses:
CALL apoc.index.search("locations", "Address.address:Paris~") YIELD node AS addr
MATCH (addr)<-[:HAS_ADDRESS]-(company:Company)
RETURN company LIMIT 50
The tilde (~) instructs the index search procedure to do a fuzzy match, allowing us to find “Paris” even if the spelling is slightly off.
We might notice that there are addresses that contain the word “Paris” that are not in Paris, France. For example there might be a Paris Street somewhere.
We can further specify that we want the text to contain both the word Paris, and the word France:
CALL apoc.index.search("locations", "+Address.address:Paris~ +France~")
YIELD node AS addr
MATCH (addr)<-[:HAS_ADDRESS]-(company:Company)
RETURN company LIMIT 50
Complex Searches
Things start to get interesting when we look at how the different entities in Paris are connected to one another. We can do that by finding all the entities with addresses in Paris, then creating all pairs of such entities and finding the shortest path between each such pair:
CALL apoc.index.search("locations", "+Address.address:Paris~ +France~") YIELD node AS addr
MATCH (addr)<-[:HAS_ADDRESS]-(company:Company)
WITH collect(company) AS companies
// create unique pairs
UNWIND companies AS x UNWIND companies AS y
WITH x, y WHERE ID(x) < ID(y)
MATCH path = shortestPath((x)-[*..10]-(y))
RETURN path
For more details on the query syntax used in the second parameter of the search
procedure,
please see this Lucene query tutorial
Utility Functions
TimeToLive (TTL) - Expire Nodes
Enable cleanup of expired nodes in neo4j.conf
with apoc.ttl.enabled=true
30s after startup an index is created:
CREATE INDEX FOR (n:TTL) ON (n.ttl)
At startup a statement is scheduled to run every 60s (or configure in neo4j.conf
- apoc.ttl.schedule=120
)
MATCH (t:TTL) where t.ttl < timestamp() WITH t LIMIT 1000 DETACH DELETE t
The ttl
property holds the time when the node is expired in milliseconds since epoch.
You can expire your nodes by setting the :TTL label and the ttl property:
MATCH (n:Foo) WHERE n.bar SET n:TTL, n.ttl = timestamp() + 10000;
Graph Algorithms
Relationship Filter
Syntax: [<]RELATIONSHIP_TYPE1[>]|[<]RELATIONSHIP_TYPE2[>]|…
| input | type | direction |
|---|---|---|
|
|
Table of Contents
OUTGOING |
|
|
Table of Contents
INCOMING |
|
|
Table of Contents
BOTH |
Label Filter
Syntax: [+-/]LABEL1|LABEL2|…
| input | label | result |
|---|---|---|
|
|
Table of Contents
include label (whitelist) |
|
|
Table of Contents
exclude label (blacklist) |
|
|
Table of Contents
stop traversal after reaching a friend (but include him) |
Centrality Algorithms
Setup
Let’s create some test data to run the Centrality algorithms on.
// create 100 nodes
FOREACH (id IN range(0,1000) | CREATE (:Node {id:id}))
// over the cross product (1M) create 100.000 relationships
MATCH (n1:Node),(n2:Node) WITH n1,n2 LIMIT 1000000 WHERE rand() < 0.1
CREATE (n1)-[:TYPE]->(n2)
PageRank Algorithm
Setup
Let’s create some test data to run the PageRank algorithm on.
// create 100 nodes
FOREACH (id IN range(0,1000) | CREATE (:Node {id:id}))
// over the cross product (1M) create 100.000 relationships
MATCH (n1:Node),(n2:Node) WITH n1,n2 LIMIT 1000000 WHERE rand() < 0.1
CREATE (n1)-[:TYPE_1]->(n2)
Graph Refactoring
In order not to have to repeatedly geocode the same thing in multiple queries, especially if the database will be used by many people, it might be a good idea to persist the results in the database so that subsequent calls can use the saved results.
Geocode and persist the result
MATCH (a:Place)
WHERE a.address IS NOT NULL AND a.latitude IS NULL
WITH a LIMIT 1000
CALL apoc.spatial.geocodeOnce(a.address) YIELD location
SET a.latitude = location.latitude
SET a.longitude = location.longitude
Note that the above command only geocodes the first 1000 ‘Place’ nodes that have not already been geocoded. This query can be run multiple times until all places are geocoded. Why would we want to do this? Two good reasons:
-
The geocoding service is a public service that can throttle or blacklist sites that hit the service too heavily, so controlling how much we do is useful.
-
The transaction is updating the database, and it is wise not to update the database with too many things in the same transaction, to avoid using up too much memory. This trick will keep the memory usage very low.
Now make use of the results in distance queries
WITH point({latitude: 48.8582532, longitude: 2.294287}) AS eiffel
MATCH (a:Place)
WHERE a.latitude IS NOT NULL AND a.longitude IS NOT NULL
WITH a, point.distance(point(a), eiffel) AS distance
WHERE distance < 5000
RETURN a.name, distance
ORDER BY distance
LIMIT 100
Combined Space and Time search
Combining spatial and date-time procedures can allow for more complex queries:
CALL apoc.date.parse('2016-06-01 00:00:00','h') YIELD value AS due_date
WITH due_date,
point({latitude: 48.8582532, longitude: 2.294287}) AS eiffel
MATCH (e:Event)
WHERE e.address IS NOT NULL AND e.datetime IS NOT NULL
CALL apoc.spatial.geocodeOnce(e.address) YIELD location
CALL apoc.date.parse(e.datetime,'h') YIELD value AS hours
WITH e, location,
distance(point(location), eiffel) AS distance,
(due_date - hours)/24.0 AS days_before_due
WHERE distance < 5000 AND days_before_due < 14 AND hours < due_date
RETURN e.name AS event, e.datetime AS date,
location.description AS description, distance
ORDER BY distance
Load JDBC
Overview: Database Integration
Data Integration is an important topic. Reading data from relational databases to create and augment data models is a very helpful exercise.
With apoc.load.jdbc
you can access any database that provides a JDBC driver, and execute queries whose results are turned into streams of rows.
Those rows can then be used to update or create graph structures.
|
load from relational database, either a full table or a sql statement |
|
load from relational database, either a full table or a sql statement |
|
register JDBC driver of source database |
To simplify the JDBC URL syntax and protect credentials, you can configure aliases in conf/neo4j.conf
:
apoc.jdbc.myDB.url=jdbc:derby:derbyDB
CALL apoc.load.jdbc('jdbc:derby:derbyDB','PERSON') becomes CALL apoc.load.jdbc('myDB','PERSON')
The 3rd value in the apoc.jdbc.<alias>.url=
effectively defines an alias to be used in apoc.load.jdbc('<alias>',….
MySQL Example
Northwind is a common example set for relational databases, which is also covered in our import guides, e.g. :play northwind graph in the Neo4j browser.
MySQL Northwind Data
select count(*) from products; +----------+ | count(*) | +----------+ | 77 | +----------+ 1 row in set (0,00 sec)
describe products; +-----------------+---------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------------+---------------+------+-----+---------+----------------+ | ProductID | int(11) | NO | PRI | NULL | auto_increment | | ProductName | varchar(40) | NO | MUL | NULL | | | SupplierID | int(11) | YES | MUL | NULL | | | CategoryID | int(11) | YES | MUL | NULL | | | QuantityPerUnit | varchar(20) | YES | | NULL | | | UnitPrice | decimal(10,4) | YES | | 0.0000 | | | UnitsInStock | smallint(2) | YES | | 0 | | | UnitsOnOrder | smallint(2) | YES | | 0 | | | ReorderLevel | smallint(2) | YES | | 0 | | | Discontinued | bit(1) | NO | | b'0' | | +-----------------+---------------+------+-----+---------+----------------+ 10 rows in set (0,00 sec)
Load JDBC Examples
cypher CALL apoc.load.driver("com.mysql.jdbc.Driver");
with "jdbc:mysql://localhost:3306/northwind?user=root" as url
cypher CALL apoc.load.jdbc(url,"products") YIELD row
RETURN count(*);
+----------+ | count(*) | +----------+ | 77 | +----------+ 1 row 23 ms
with "jdbc:mysql://localhost:3306/northwind?user=root" as url
cypher CALL apoc.load.jdbc(url,"products") YIELD row
RETURN row limit 1;
+--------------------------------------------------------------------------------+ | row | +--------------------------------------------------------------------------------+ | {UnitPrice -> 18.0000, UnitsOnOrder -> 0, CategoryID -> 1, UnitsInStock -> 39} | +--------------------------------------------------------------------------------+ 1 row 10 ms
Load data in transactional batches
You can load data from jdbc and create/update the graph using the query results in batches (and in parallel).
CALL apoc.periodic.iterate('
call apoc.load.jdbc("jdbc:mysql://localhost:3306/northwind?user=root","company")',
'CREATE (p:Person) SET p += value', {batchSize:10000, parallel:true})
RETURN batches, total
Cassandra Example
Setup Song database as initial dataset
curl -OL https://raw.githubusercontent.com/neo4j-contrib/neo4j-cassandra-connector/master/db_gen/playlist.cql curl -OL https://raw.githubusercontent.com/neo4j-contrib/neo4j-cassandra-connector/master/db_gen/artists.csv curl -OL https://raw.githubusercontent.com/neo4j-contrib/neo4j-cassandra-connector/master/db_gen/songs.csv $CASSANDRA_HOME/bin/cassandra $CASSANDRA_HOME/bin/cqlsh -f playlist.cql
Download the Cassandra JDBC Wrapper, and put it into your $NEO4J_HOME/plugins
directory.
Add this config option to $NEO4J_HOME/conf/neo4j.conf
to make it easier to interact with the cassandra instance.
apoc.jdbc.cassandra_songs.url=jdbc:cassandra://localhost:9042/playlist
Restart the server.
Now you can inspect the data in Cassandra with.
CALL apoc.load.jdbc('cassandra_songs','artists_by_first_letter') yield row
RETURN count(*);
╒════════╕ │count(*)│ ╞════════╡ │3605 │ └────────┘
CALL apoc.load.jdbc('cassandra_songs','artists_by_first_letter') yield row
RETURN row LIMIT 5;
CALL apoc.load.jdbc('cassandra_songs','artists_by_first_letter') yield row
RETURN row.first_letter, row.artist LIMIT 5;
╒════════════════╤═══════════════════════════════╕ │row.first_letter│row.artist │ ╞════════════════╪═══════════════════════════════╡ │C │C.W. Stoneking │ ├────────────────┼───────────────────────────────┤ │C │CH2K │ ├────────────────┼───────────────────────────────┤ │C │CHARLIE HUNTER WITH LEON PARKER│ ├────────────────┼───────────────────────────────┤ │C │Calvin Harris │ ├────────────────┼───────────────────────────────┤ │C │Camané │ └────────────────┴───────────────────────────────┘
Let’s create some graph data, we have a look at the track_by_artist table, which contains about 60k records.
CALL apoc.load.jdbc('cassandra_songs','track_by_artist') yield row RETURN count(*);
CALL apoc.load.jdbc('cassandra_songs','track_by_artist') yield row
RETURN row LIMIT 5;
CALL apoc.load.jdbc('cassandra_songs','track_by_artist') yield row
RETURN row.track_id, row.track_length_in_seconds, row.track, row.music_file, row.genre, row.artist, row.starred LIMIT 2;
╒════════════════════════════════════╤══════╤════════════════╤══════════════════╤═════════╤════════════════════════════╤═══════════╕ │row.track_id │length│row.track │row.music_file │row.genre│row.artist │row.starred│ ╞════════════════════════════════════╪══════╪════════════════╪══════════════════╪═════════╪════════════════════════════╪═══════════╡ │c0693b1e-0eaa-4e81-b23f-b083db303842│219 │1913 Massacre │TRYKHMD128F934154C│folk │Woody Guthrie & Jack Elliott│false │ ├────────────────────────────────────┼──────┼────────────────┼──────────────────┼─────────┼────────────────────────────┼───────────┤ │7d114937-0bc7-41c7-8e0c-94b5654ac77f│178 │Alabammy Bound │TRMQLPV128F934152B│folk │Woody Guthrie & Jack Elliott│false │ └────────────────────────────────────┴──────┴────────────────┴──────────────────┴─────────┴────────────────────────────┴───────────┘
Let’s create some indexes and constraints, note that other indexes and constraints will be dropped by this.
CALL apoc.schema.assert(
{Track:['title','length']},
{Artist:['name'],Track:['id'],Genre:['name']});
╒════════════╤═══════╤══════╤═══════╕ │label │key │unique│action │ ╞════════════╪═══════╪══════╪═══════╡ │Track │title │false │CREATED│ ├────────────┼───────┼──────┼───────┤ │Track │length │false │CREATED│ ├────────────┼───────┼──────┼───────┤ │Artist │name │true │CREATED│ ├────────────┼───────┼──────┼───────┤ │Genre │name │true │CREATED│ ├────────────┼───────┼──────┼───────┤ │Track │id │true │CREATED│ └────────────┴───────┴──────┴───────┘
CALL apoc.load.jdbc('cassandra_songs','track_by_artist') yield row
MERGE (a:Artist {name:row.artist})
MERGE (g:Genre {name:row.genre})
CREATE (t:Track {id:toString(row.track_id), title:row.track, length:row.track_length_in_seconds})
CREATE (a)-[:PERFORMED]->(t)
CREATE (t)-[:GENRE]->(g);
Added 63213 labels, created 63213 nodes, set 182413 properties, created 119200 relationships, statement executed in 40076 ms.
LOAD JDBC - Resources
To use other JDBC drivers use these download links and JDBC URL.
Put the JDBC driver into the $NEO4J_HOME/plugins
directory and configure the JDBC-URL in $NEO4J_HOME/conf/neo4j.conf
with apoc.jdbc.<alias>.url=<jdbc-url>
| Database | JDBC-URL | Driver Source |
|---|---|---|
Table of Contents
MySQL |
|
Table of Contents
|
Table of Contents
Postgres |
|
Table of Contents
|
Table of Contents
Oracle |
|
Table of Contents
|
Table of Contents
MS SQLServer |
|
Table of Contents
|
Table of Contents
IBM DB2 |
|
Table of Contents
|
Table of Contents
Derby |
|
Table of Contents
Included in JDK6-8 |
Table of Contents
Cassandra |
|
Table of Contents
|
There are a number of blog posts / examples that details usage of apoc.load.jdbc
Streaming Data to Gephi
|
streams provided data to Gephi |
Notes
Gephi has a streaming plugin, that can provide and accept JSON-graph-data in a streaming fashion.
Make sure to install the plugin firsrt and activate it for your workspace (there is a new "Streaming"-tab besides "Layout"), right-click "Master"→"start" to start the server.
You can provide your workspace name (you might want to rename it before you start thes streaming), otherwise it defaults to workspace0
The default Gephi-URL is http://localhost:8080, resulting in http://localhost:8080/workspace0?operation=updateGraph
You can also configure it in conf/neo4j.conf
via apoc.gephi.url=url
or apoc.gephi.<key>.url=url
Example
match path = (:Person)-[:ACTED_IN]->(:Movie)
WITH path LIMIT 1000
with collect(path) as paths
call apoc.gephi.add(null,'workspace0', paths) yield nodes, relationships, time
return nodes, relationships, time
Format
We send all nodes and relationships of the passed in data convert into individual Gephi-Streaming JSON fragements, separated by \r\n
.
{"an":{"123":{"TYPE":"Person:Actor","label":"Tom Hanks", x:333,y:222,r:0.1,g:0.3,b:0.5}}}\r\n
{"an":{"345":{"TYPE":"Movie","label":"Forrest Gump", x:234,y:122,r:0.2,g:0.2,b:0.7}}}\r\n
{"ae":{"3344":{"TYPE":"ACTED_IN","label":"Tom Hanks",source:"123",target:"345","directed":true,r:0.1,g:0.3,b:0.5}}}
Specifics Details
Gephi doesn’t render the graph data unless you also provide x,y coordinates in the payload, so we just send random ones within a 1000x1000 grid.
We also generate colors per label combination and relationship-type, both of which are also transferred as TYPE
property.
ElasticSearch Integration
|
elastic search statistics |
|
perform a GET operation |
|
perform a SEARCH operation |
|
perform a raw GET operation |
|
perform a raw POST operation |
|
perform a POST operation |
|
perform a PUT operation |
Example
call apoc.es.post("localhost","tweets","users","1",null,{name:"Chris"})
call apoc.es.get("localhost","tweets","users","1",null,null)
call apoc.es.stats("localhost")
General Structure and Parameters
call apoc.es.post(host-or-port,index-or-null,type-or-null,id-or-null,query-or-null,payload-or-null) yield value
// GET/PUT/POST url/index/type/id?query -d payload
host or port parameter
The parameter can be a direct host or url, or an entry to be lookup up in neo4j.conf
-
host
-
host:port
-
lookup via key to apoc.es.<key>.url
-
lookup via key apoc.es.<key>.host
-
lookup apoc.es.url
-
lookup apoc.es.host
index parameter
Main ES index, will be sent directly, if null then "_all" multiple indexes can be separated by comma in the string.
type parameter
Document type, will be sent directly, if null then "_all" multiple types can be separated by comma in the string.
id parameter
Document id, will be left off when null.
query parameter
Query can be a map which is turned into a query string, a direct string or null then it is left off.
payload parameter
Payload can be a map which will be turned into a json payload or a string which will be sent directly or null.
Results
Results are stream of map in value.
Load XML
Load XML Introduction
Many existing (enterprise) applications, endpoints and files use XML as data exchange format.
To make these datastructures available to Cypher, you can use apoc.load.xml
.
It takes a file or http URL and parses the XML into a map datastructure.
See the following usage-examples for the procedures.
Example File
"How do you access XML doc attributes in children fields ?"
(Thanks Nicolas Rouyer)
For example, if my XML file is the example book.xml provided by Microsoft.
<?xml version="1.0"?>
<catalog>
<book id="bk101">
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>An in-depth look at creating applications
with XML.</description>
</book>
<book id="bk102">
<author>Ralls, Kim</author>
<title>Midnight Rain</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
<description>A former architect battles corporate zombies,
...
We have the file here, on GitHub.
Load XML and Introspect
Let’s just load it and see what it looks like.
It’s returned as value map with nested _type
and _children
fields, per group of elements.
Attributes are turned into map-entries.
And each element into their own little map with _type
, attributes and _children
if applicable.
call apoc.load.xml("https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/master/src/test/resources/books.xml")
{_type: catalog, _children: [
{_type: book, id: bk101, _children: [
{_type: author, _text: Gambardella, Matthew},
{_type: title, _text: XML Developer's Guide},
{_type: genre, _text: Computer},
{_type: price, _text: 44.95},
{_type: publish_date, _text: 2000-10-01},
{_type: description, _text: An in-depth look at creating applications ....
For each book, how do I access book id ?
You can access attributes per element directly.
call apoc.load.xml("https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/master/src/test/resources/books.xml") yield value as catalog
UNWIND catalog._children as book
RETURN book.id
╒═══════╕ │book.id│ ╞═══════╡ │bk101 │ ├───────┤ │bk102 │
For each book, how do I access book author and title ?
Filter into collection
You have to filter over the sub-elements in the _childrens
array in this case.
call apoc.load.xml("https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/master/src/test/resources/books.xml") yield value as catalog
UNWIND catalog._children as book
RETURN book.id, [attr IN book._children WHERE attr._type IN ['author','title'] | [attr._type, attr._text]] as pairs
╒═══════╤════════════════════════════════════════════════════════════════════════╕ │book.id│pairs │ ╞═══════╪════════════════════════════════════════════════════════════════════════╡ │bk101 │[[author, Gambardella, Matthew], [title, XML Developer's Guide]] │ ├───────┼────────────────────────────────────────────────────────────────────────┤ │bk102 │[[author, Ralls, Kim], [title, Midnight Rain]] │
How do I return collection elements?
This is not too nice, we could also just have returned the values and then grabbed them out of the list, but that relies on element-order.
call apoc.load.xml("https://raw.githubusercontent.com/neo4j-contrib/neo4j-apoc-procedures/master/src/test/resources/books.xml") yield value as catalog
UNWIND catalog._children as book
WITH book.id as id, [attr IN book._children WHERE attr._type IN ['author','title'] | attr._text] as pairs
RETURN id, pairs[0] as author, pairs[1] as title
╒═════╤════════════════════╤══════════════════════════════╕ │id │author │title │ ╞═════╪════════════════════╪══════════════════════════════╡ │bk101│Gambardella, Matthew│XML Developer's Guide │ ├─────┼────────────────────┼──────────────────────────────┤ │bk102│Ralls, Kim │Midnight Rain │
Cypher Operations
Running Cypher fragments
We can use Cypher as safe, graph-aware, partially compiled scripting language within APOC.
Cypher Execution
|
runs each statement in the file, all semicolon separated - currently no schema operations |
|
executes fragment in parallel batches with the list segments being assigned to _ |
Example: Fast Node-Counts by Label
Counts by label are quickly provided by the counts-store, but only if they are the the single thing in the query, like
MATCH (:Person) RETURN count(*);
It also works to combine several with UNION ALL
, but not via WITH
MATCH (:Person) WITH count(*) as people
MATCH (:Movie) RETURN people, count(*) as movies;
MATCH (:Person) RETURN count(*)
UNION ALL
MATCH (:Movie) RETURN count(*);
But with apoc.cypher.run
we can construct the statement and run each of them individually, so it completes in a few ms.
call db.labels() yield label
call apoc.cypher.run("match (:`"+label+"`) return count(*) as count", null) yield value
return label, value.count as count
You can use a similar approach to get the property-keys per label:
CALL db.labels() yield label
call apoc.cypher.run("MATCH (n:`"+label+"`) RETURN keys(n) as keys LIMIT 1",null) yield value
RETURN label, value.keys as keys
Job management and periodic execution
Introduction asynchronous transactional execution
|
Note
|
this document is work in progress |
Cypher is great for querying graphs and importing and updating graph structures.
While during imports you can use PERIODIC COMMIT
to control transaction sizes in memory,
for other graph refactorings it’s not that easy to commit transactions regularly to free memory for new update state.
Also sometimes you want to schedule execution of Cypher statements to run regularly in the background or asynchronously ("fire & forget").
The apoc.periodic.*
procedures provide such capabilities.


Edie
Unhappy with your homepage?
We create beautiful and fast web services
Story, emotion and purpose
We help transform your ideas into real world applications that will outperform your toughest competition and help you achieve your strategic goals in short period of time.
Want us to contact you?


[1]
Good hardrive, minus all its features.; Absolutly terrible software.
[2]
price seems good; too slow, no response


AppRun is a library for developing applications using the elm style model-view-update
architecture based on event pub and sub pattern.
This is a demo application built using AppRun to mimic a single page business application. It has 8 compoments:
- Hello world: a component binds input to div
- Counter: simple counter
- Counters: multiple counters with history
- Drag: a dragable div
- Todo: a component of todo app, with undo and redo
- Type-ahead: use type-ahead to create a selection list
- Benchmark: test performance, execution time logged in console
- Hacker News: a component of hacker news reader
Click the links get started.


Go to the source code of this file.
|
| | SC_DEFINE_MESSAGE (SC_ID_TRACING_FOPEN_FAILED_, 701, "cannot open trace file for writing") SC_DEFINE_MESSAGE(SC_ID_TRACING_TIMESCALE_DEFAULT_ |
| |
| default timescale unit used for tracing | SC_DEFINE_MESSAGE (SC_ID_TRACING_TIMESCALE_UNIT_, 703, "tracing timescale unit set") SC_DEFINE_MESSAGE(SC_ID_TRACING_VCD_DELTA_CYCLE_ |
| |
| default timescale unit used for tracing VCD delta cycle tracing with pseudo | timesteps (1 unit)" ) SC_DEFINE_MESSAGE( SC_ID_TRACING_INVALID_TIMESCALE_UNIT_ |
| |
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set | SC_DEFINE_MESSAGE (SC_ID_TRACING_OBJECT_IGNORED_, 710, "object cannot not be traced") SC_DEFINE_MESSAGE(SC_ID_TRACING_OBJECT_NAME_FILTERED_ |
| |
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered | SC_DEFINE_MESSAGE (SC_ID_TRACING_INVALID_ENUM_VALUE_, 712, "traced value of enumerated type undefined") SC_DEFINE_MESSAGE(SC_ID_TRACING_VCD_TIME_RESOLUTION_ |
| |
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered current kernel time is not representable in VCD time units | SC_DEFINE_MESSAGE (SC_ID_TRACING_REVERSED_TIME_, 714, "tracing cycle with duplicate or reversed time detected") SC_DEFINE_MESSAGE(SC_ID_TRACING_CLOSE_EMPTY_FILE_ |
| |
|
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered current kernel time is not representable in VCD time units trace file closed before any cycles were | traced |
| |
◆ SC_DEFINE_MESSAGE
| #define SC_DEFINE_MESSAGE |
( |
|
id, |
|
|
|
unused1, |
|
|
|
unused2 |
|
) |
| namespace sc_core { extern SC_API const char id[]; } |
◆ SC_DEFINE_MESSAGE() [1/5]
| SC_DEFINE_MESSAGE |
( |
SC_ID_TRACING_FOPEN_FAILED_ |
, |
|
|
701 |
, |
|
|
"cannot open trace file for writing" |
|
|
) |
| |
◆ SC_DEFINE_MESSAGE() [2/5]
| default timescale unit used for tracing SC_DEFINE_MESSAGE |
( |
SC_ID_TRACING_TIMESCALE_UNIT_ |
, |
|
|
703 |
, |
|
|
"tracing timescale unit set" |
|
|
) |
| |
◆ SC_DEFINE_MESSAGE() [3/5]
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set SC_DEFINE_MESSAGE |
( |
SC_ID_TRACING_OBJECT_IGNORED_ |
, |
|
|
710 |
, |
|
|
"object cannot not be traced" |
|
|
) |
| |
◆ SC_DEFINE_MESSAGE() [4/5]
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered SC_DEFINE_MESSAGE |
( |
SC_ID_TRACING_INVALID_ENUM_VALUE_ |
, |
|
|
712 |
, |
|
|
"traced value of enumerated type undefined" |
|
|
) |
| |
◆ SC_DEFINE_MESSAGE() [5/5]
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered current kernel time is not representable in VCD time units SC_DEFINE_MESSAGE |
( |
SC_ID_TRACING_REVERSED_TIME_ |
, |
|
|
714 |
, |
|
|
"tracing cycle with duplicate or reversed time detected" |
|
|
) |
| |
◆ timesteps()
| default timescale unit used for tracing VCD delta cycle tracing with pseudo timesteps |
( |
1 |
unit | ) |
|
◆ traced
| default timescale unit used for tracing VCD delta cycle tracing with pseudo invalid tracing timescale unit set traced object name filtered current kernel time is not representable in VCD time units trace file closed before any cycles were traced |


Hello, we’re TripWithUs! your premium travel planning service. We know you’re always busy. No time for organizing a trip to your dream city that you always wanted to explore. So let us take care of that, we’re really good at it, we promise!
Explore best places around the U.S. with us! Ranging from Prince William Sound located in the heart of Chugach National forest in Alaska to Congress Avenue in the downtown Austin, Texas. For each of these locations we provide you with the information you care about!
Explore more places here
Explore our expert recommendations on nearby live events, festivals, tours, and music concerts around the U.S. with us! Get promo codes, best deals and discounts! After all, what completes your trip but a gala time at a fun event with family and friends!
Explore more events here


Osprey basis set tools¶
Being a linear-combination modelling software, Osprey requires prior spectral knowledge in the form of so-called basis sets. These are collections of model spectra (basis functions) for the various metabolites you wish to quantify.
Historically, basis functions were acquired experimentally from aqueous solutions, which was a laborious and often incredibly frustrating task. Fortunately, many free software solutions open up a world of simulating any NMR experiment, and can generate noise-free model spectra of most of the spin systems we could be interested in.
In this chapter, you will learn how to generate an Osprey basis set. You can either import an existing complete basis set in LCModel format (.BASIS
), or you can compile an Osprey basis set from a set of synthetic spectra that have been simulated using the FID-A software. Please refer to the example scripts in the repository for directions and how to do this. You can also ask for advice in the Spectral Simulation and Basis Sets categories of the MRSHub forum.
io_LCMBasis¶
If you have an existing LCModel basis set (.BASIS
), you can import it into Osprey. Assuming the basis set is located at /Users/Georg/LCModelBasissets/GE/press144
, you can execute the following command at the MATLAB prompt after you have run OspreyJob
:
>> file = '/Users/Georg/LCModelBasissets/GE/press144';
You can then call Osprey's io_LCMBasis
function to create a basis set:
>> [BASIS] = io_LCMBasis(file, 1, 'unedited', 'none');
Follow the instructions in the MATLAB prompt, and from then on, OspreyFit will automatically pick this basis set, but only if there is no internal existing Osprey basis set with matching parameters. We will soon provide the option to specify an individual basis set in the job file.
fit_makeBasis¶
For the purpose of this tutorial, we will assume that you have a set of FID-A simulations saved in a folder on your hard drive. Your folder may look like this:
In this case, we have simulated a bunch of metabolites for the GE PRESS sequence at an echo time of 144 ms.
If this folder is located at, say, /Users/Georg/MRS_Simulations/GE/press144
, you can create a variable called folder
at the MATLAB prompt:
>> folder = '/Users/Georg/MRS_Simulations/GE/press144';
You can then call Osprey's fit_makeBasis
function to create a basis set:
>> [BASIS] = fit_makeBasis(folder, 1, 'unedited');
This will generate a struct array called BASIS
in the MATLAB workspace, and also save it to the current MATLAB working directory. This file is your new Osprey basis set. If the addMMFlag
argument (see below) is set to 1
, the filename of the basis set is going to be BASIS_MM.mat
; if it is set to 0
, the filename will be BASIS_noMM.mat
.
Complete syntax¶
>> [BASIS] = fit_makeBasis(folder, addMMFlag, sequence, editTarget);
Inputs¶
| Input | Type | Description | Mandatory? | Options |
|---|---|---|---|---|
| folder | String | Complete path to the folder containing .MAT files with FID-A-simulated metabolite basis functions |
Yes | --- |
| addMMFlag | Boolean | If set to 1 (default), Osprey will automatically add macromolecule and lipid basis functions to the basis set |
No | 1 (default), 0 |
| sequence | String | Determines the type of sequence that you want to create a basis set for. Will try to automatically determine the order of editing steps from saturated NAA and water signals. | No | 'unedited' (default), 'MEGA' , 'HERMES' , 'HERCULES' |
| editTarget | String | Determines the target molecule(s) of the editing experiment. Only needs to be set if sequence is set to something other than 'unedited' . |
No | 'GABA' (default), 'GSH' |
Outputs¶
| Output | Type | Description | Mandatory? | Options |
|---|---|---|---|---|
| BASIS | Struct | Structure containing the Osprey basis set. | Yes | --- |
fit_plotBasis¶
Once you have generated the basis set, you may want to plot the basis functions and inspect that they look like you expect them to. For this purpose, Osprey includes a function called fit_plotBasis
.
fit_plotBasis
acts on the contents of an Osprey .MAT
basis set file. If you load any basis set into MATLAB by double-clicking on it, you will see the struct BASIS
in the MATLAB workspace:
You can then call fit_plotBasis
to create a plot overview of the basis set:
>> fit_plotBasis(BASIS, 1, 1);
This command will generate a stack plot of all basis functions (including macromolecules and lipids, if you have chosen to include them in the basis set) along with a ppm axis:
Complete syntax¶
>> out = fit_plotBasis(basisSet, dim, stagFlag, ppmmin, ppmmax, xlab, ylab, figTitle);
Inputs¶
| Input | Type | Description | Mandatory? | Options |
|---|---|---|---|---|
| basisSet | String | Name of the struct in the MATLAB workspace containing the Osprey basis set (usually BASIS ) |
Yes | --- |
| dim | Integer | Dimension of the basis function that you want to plot. For unedited data, this will be 1 . MEGA-edited data will have the off spectrum in dimension 1, the on spectrum in dimension 2, the difference spectrum in dimension 3, and the sum spectrum in dimension 4. |
No | Default: 1 |
| stagFlag | Boolean | Determines whether basis functions are plotted vertically staggered or simply on top of one another. | No | 1 = staggered (default), 0 (not staggered) |
| ppmmin | Float | Lower limit of ppm axis to plot. | No | Default: 0.2 |
| ppmmax | Float | Upper limit of ppm axis to plot. | No | Default: 5.2 |
| xlab | String | X-axis label | No | Default: 'Frequency (ppm)' |
| ylab | String | Y-axis label | No | Default: '' |
| figTitle | String | Figure title | No | Default: '' |
Outputs¶
| Output | Type | Description | Mandatory? | Options |
|---|---|---|---|---|
| out | Figure handle | Figure handle for the output figure | Yes | --- |


« Previous Demo:
Interactive SVG Infographic
Back to the Codrops Article
HexaFlip
Try dragging some cubes with your mouse.
Demo 1
Demo 2
Demo 3
Demo 4


The 2nd edition of the International Conference on Communication, VLSI and Signal Processing (ICCVSP-2020) will be held at Electronics & Communication Engineering Department Siddaganga Institute of Technology Tumakuru-572103, India, on Sep 4th and 5th, 2020. ICCVSP, shall provide a new forum for the world-class researchers to gather and share their research achievements, ideas and progress that is required to solve the future challenges that the VLSI, Communication and Signal Processing field face. In addition to a rich variety of regular technical sessions (Call for papers), the conference program will include plenary sessions featuring world-class speakers covering the most recent topics.
Desktop site recommended


C++ GUI Programming with QT.
CS311 • Fall 2021 • Euromed University
QT is a compressive C++ framework for developing cross-platform GUI applications. The library uses the Write Once, Compile Everywhere paradigm. It allows programmers to use a single source tree for applications that could run on Window, Mac Os and Linux which makes perfect for embedded systems like Rasberry Pi.
The purpose of this course is to teach students to write GUI programs using Qt5. We will start by reviewing advanced OOP mechanisms (like polymorphism and inheritance) of modern C++ using the 14 standard. After that, the student will start with a simple “Hello Qt” dialog and quickly dive into more advanced topic like slots and signals. The final project consist of creating a simple spreadsheet application with a set of useful capabilities.
Upon completion of this course, you should be able to
- Confidently use C++ OOP paradigms
- Create its own dialogs and applications.
- Extend the concept of signals and slots to more event driven programming challenges.
- Time: Monday/Tuesday/Wednesday/Thursday 08:30-12:00 am
- Location: Center B4.
- Discussion and QA: Piazza
- Contact: For external enquiries, personal matters or in emergencies, you can email me at<EMAIL_ADDRESS>- Instructor Anass Belcaid
- Email<EMAIL_ADDRESS>- Office hours: Monday, Wednesday 04:00-06:00pm
Announcements
| Aug 19, 2019 | Formal Course Description |


--- layout: archive title: Zulip Chat Archive permalink: /stream/116395-maths/topic/has_div.20for.20groups.html ---
Is there a particular reason why we have has_sub
for add_group
s, but not has_div
for group
s?
because you don't write a/b
for a, b \in G
you might wonder why division isn't defined for groups, and this is one of the differences from add_groups, which have subtraction, but there is a difference between the total division on groups and the almost total division on fields and it doesn't seem to be helpful to unify them; lots of theorems overlap with a name conflict, but they are all proven differently
:point_up: Mario Carneiro, 15/01/2019 12:24:17 (UTC)
{% endraw %}Last updated: Apr 24 2020 at 19:02 UTC


B3G2 Realty
Home
Post Property
Purchase Property
Rent Property
Other Services
Information
Action
Another action
Something else here
Welcome to B3g2 Real Estate
Smart Contract
Singapore 1st Block Chain Technology in Real Estate
Add and list your property details
Previous
Next
Email Address:
Contact Number:
Location:
Postal Code:
City:
Agent Fee:
Cost:
Property Type:
Select
HDB
Condo
Landed
District:
Select
D01
D02
D03
Lawyer:
Select
1. Law1 Legal Firm
2. Law2 Legal Co
3. Law3 Firm
4. Law4 Firm
5. Law5 Firm
Bedroom and bathrooms:
Select
Studio
1B1T
2B1T
3B2T
4B3T
Total area (sqf):
Upload a file:


Randomly select a Superhero!
Click to select a Super Hero
Guess what Publisher I'm from!
Marvel Comics, DC Comics, etc....
Submit