The Object Network

The idea of the Object Network is to provide a simple and powerful way to build and connect systems.

The Object Network has four elements:

The above are described in either JSON or Cyrus notation. The Cyrus notation is a much simplified form of JSON. FOREST is defined through the application/forest+json and text/cyrus proposed Media Types. It also works fine using just application/json.

There is a reference implementation in Java for servers and Android (NetMash), and a Javascript client.

Functional Observer

Functional Observer describes a linked object graph structure - the Object Network. The Objects are essentially JSON structures: lists, maps, strings, etc. Here's an example in JSON and in the cleaner Cyrus notation:

{ "b": ["c", "x", 123, "y"], "d": true }

{ b: c x 123 y  d: true }

As you can see, single elements and single-element lists are not distinguished, and string numbers and booleans aren't distinguished from native numbers and booleans. Also, null elements disappear.

All Object Network objects have UID object references which will usually contain a GUID, a UUID or some other random-looking string after a "uid-" prefix. Links are just UID or URL strings as values after a property tag and can appear anywhere in an object. Links are transparent: so any object linked to can be merged in-line instead:

uid-111:

{ b: c  f: uid-222 }

uid-222:

{ a: x  b: e 123 }

=

{ b: c  f: { a: x  b: e 123 }}

Objects (and sub-objects) can link to "further details" using More:

uid-111:

{ b: c  More: uid-222 }

uid-222:

{ a: x  b: e 123 }

=

{ a: x  b: c e 123 }

The elements at 'More:' are merged in set-wise: duplicates are removed.

These objects interact by mutual observation. The Functional Observer interaction model is simply:

Set an object's state as a Function of its current state plus the state of other objects it Observes through links.

This observation occurs through either pull or push of linked object state.

Such a programming model is declarative in nature, and thus very expressive, as well as being naturally concurrent.

FOREST

FOREST is a distributed object architecture. FOREST is an acronym for Functional Observer REST: it maps directly to RESTful distribution over HTTP, using GET for pull and POST for push of object state, in both directions between interacting peer servers. POST is effectively an idempotent GET response or cache update. Even though HTTP is client-server and doesn't have notification, FOREST implements a symmetric peer-to-peer protocol over HTTP's GET and POST. Each server can act as client; GET is used to pull data, POST to notify updates to that data. PUT, DELETE, etc aren't used. HEAD may be used.

Objects are published into a global interacting object network by turning their UIDs into URLs. A link can be a full URL starting "http://", or just a UID starting "uid-". UIDs can be converted to full URLs by wrapping them appropriately with prefix and postfix - e.g. uid-0fe6-7d5d can be wrapped to give: http://the-object.net/events/uid-0fe6-7d5d.cyr. Object Network URLs are considered opaque to clients. If a URL returns text/cyrus it may end in ".cyr", the extension for this format. If you replace that with ".json", you should get the familiar more verbose and noisy form. The use of these extensions is optional but advised for human readability, editing and saving of files.

See the main FOREST site for more detail, defined through the application/forest+json Media Type.

Cyrus Notation and Language

Broadly speaking, Cyrus notation is JSON without unnecessary quotes, commas and list brackets. It's always UTF-8 (no BOM!). The top level item is always an object. It's ordered, meaning that random re-orderings of properties due to hashtable algorithms won't occur, and properties are generally dealt with top-down. There are no duplicates allowed in property tag labels. (In practical terms, that means using LinkedHashMap, etc., in implementations.)

The Cyrus Language is a simple functional/rule programming language in this notation for animating the objects.

Object Network Types

The Object Network Types are a set of formats for common object types and their interactions and behaviours.

The main property is "is" - which is a list of labels giving the object a type. There may be many types "mixed in" to an object, raising expectations of (a) the presence of certain properties (b) the presence of certain behaviours, and/or (c) the ability to react to, or interest in observing, certain peer types.

Most fields will be defined within the type or format that an object "is", but many will stand alone. For example, "title" is something that will mean the same in any format, as will "location", and other common fields, such as "created" and "author".

The semantics, if not the exact syntax, of certain fields will usually be declared in the Object Network as being defined in some other standard (e.g. events by iCalendar). Almost by definition we don't have namespacing in the Object Net Types. The whole point is to encourage discussion and agreement, not isolation.

The remainder of this page shows a number of examples, applications and patterns using the Object Network Type formats in Cyrus format, and using the Cyrus Language.

It's currently being edited, by the way, and should not be taken as usefully stable until I start talking about it on my blog and on Twitter!

Event

An Event type carries a time period and optional location for an event. It can be used for calendar events, and can be mapped onto iCalendar:

{ URL: http://the-object.net/events/uid-f330a3-4011e.cyr
  is: attendable event
  title: "The Object Network Conference"
  content: "This year is expected to be the best yet!"
  start: "30 Sep 2016 09:00:00 GMT"
  end:   " 1 Oct 2016 23:00:00 GMT"
  location: http://bletchleypark.org/address.cyr
  attendees: uid-0fe6-7d5d
}

An Event type may normally be just "event", but here it's an "attendable event", because it's expecting RSVPs. The attendable type is a "mixin" that indicates the type of object this object is interested in.

The "start" and "end" properties map onto iCalendar's "DTSTART" and "DTEND".

The "location" is the URL of a contact type (is: contact). The "attendees" property is a list of links to the contact objects of the attendees.

RSVP

Since this Event is attendable, you know you can reply, to be hopefully added to the list of attendees, with an RSVP type:

{ URL: http://fred.info/o/uid-f330a3-4011e.cyr
  is: rsvp
  event: http://the-object.net/events/uid-f330a3-4011e.cyr
  person: http://..
  attending: yes
  Notifying: http://the-object.net/events/uid-f330a3-4011e.cyr
}

This RSVP is hosted on fred.info, not the-object.net like the event itself. It is a persistent, updatable state, that is Notifying itself to the event.

Cyrus Language Rule

When this RSVP is received at the event, there can be a Cyrus Language Rule type to handle it that may look like this:

{ URL: http://the-object.net/rules/uid-34-234-23-23.cyr
  is: attendable event rule
  when: "RSVP attending received ensure user is in attendees"
  Alerted: { is: rsvp  event: @  attending: yes }
  attendees: => @. with @Alerted
}

The Alerted property is the other end of Notifying - it's a link to the RSVP, and in the rule, you can jump right into the content to match its properties. Its event property is @, which means a link to the current object. The attendees property becomes (=>) itself (@.) but with the Alerted link if it's not already there

Here's the rule for removing someone who is no longer attending:

{ URL: http://the-object.net/rules/uid-fa82-a11-003.cyr
  is: attendable event rule
  when: "RSVP not attending ensure user not in attendees"
  attendees: { attending: no } => #
}

The link to an RSVP that is no longer attending becomes nothing (#).

The rules are attached to the event they animate by links:

{ URL: http://the-object.net/events/uid-f330a3-4011e.cyr
  is: attendable event
  Rules: uid-34-234-23-23 uid-fa82-a11-003
  title: "The Object Network Conference"
  :
}

The Cyrus Language has its own website.

Nested Event

An Event can have sub-events - for example, a conference has many talks. These are represented by the sub-objects/within pattern that is available for all types:

{ UID: uid-0112-09a9-3f54-b720
  is: attendable event
  title: "Geek Speak December"
  text: "Europe's Top Tech"
  start: "Wed 12 Dec 2012 18:00:00 GMT"
  end:   "Wed 12 Dec 2012 23:00:00 GMT"
  sub-objects: uid-3e0e-a630-b669-23d7 uid-0a01-cec7-61b7-a770
}

{ UID: uid-3e0e-a630-b669-23d7
  is: event
  title: "My Love of Clojure"
  text: "Long ago, I fell in love with Lisp.."
  start: "Wed 12 Dec 2012 18:00:00 GMT"
  end:   "Wed 12 Dec 2012 19:00:00 GMT"
  within: uid-0112-09a9-3f54-b720
}

Reviewable Event

An Event can be ratable and reviewable by adding is: rateable and a gui view:

{ UID: uid-3e0e-a630-b669-23d7
  is: rateable gui event
  title: "My Love of Clojure"
  text: "Long ago, I fell in love with Lisp.."
  start: "Wed 12 Dec 2012 18:00:00 GMT"
  end:   "Wed 12 Dec 2012 19:00:00 GMT"
  within: uid-0112-09a9-3f54-b720
  view: {
    email:      { input: textfield label: "Your Email:" }
    comments:   { input: textfield label: "Comments:" }
    pres-style: { input: rating    label: "Presentation Style:" }
  }
}

This expects an RSVP/form type back:

{ UID: uid-3e0e-a630-b669-23d7
  is: rsvp form
  event: uid-3e0e-a630-b669-23d7
  within: http://..
  rating: 5
  form:{
    email: foo@bar.com
    comments: "A good show.."
    pres-style: 4
  }
}

Contact

The Contact type is based on vCard:

A minimal contact:

{ is: contact
  name: {
    given:  Duncan
    middle: Beaumont
    family: Cragg
  }
  address: {
      locality: "Kingston-upon-Thames"
      region: Surrey
      postal-code: "KT1"
      country: UK
  }
  email: demo@cilux.org
}

A maximal contact:

{ is: contact
  name: {
    given:  Duncan
    middle: Beaumont
    family: Cragg
  }
  full-name: "Mr Duncan Cragg"
  address: {
      locality: "Kingston-upon-Thames"
      region: Surrey
      postal-code: "KT1"
      country: UK
  }
  email: demo@cilux.org
  organisation: {
      full-name: "ThoughtWorks (UK) Ltd"
      web-view: http://www.thoughtworks.com
      More: http://forest-roa.org/567-890.json
  }
  birthday: 1964-01-01
  web-view:
      http://duncan-cragg.org/blog/
      http://twitter.com/duncancragg
  publications:
      http://rd.springer.com/export-citation/chapter/10.1007/978-1-4419-8303-9_7.json
      http://the-object.net/111-111.json
      http://duncan-cragg.org/blog/atom.cyr
      http://duncan-cragg.org/blog/
  bio: "Creator of the [Object Network][http://the-object.net] and Object-Mash"
  attending:
       http://the-object.net/123-456.json
       http://api2.the-object.net/lanyrd/2013/overtheair.json
  employer:
       http://forest-roa.org/567-890.json
  inspirations:
        http://api2.the-object.net/dbpedia/Tim_Berners-Lee.json
        http://api2.the-object.net/dbpedia/Alan_Turing.json
  More: http://api2.the-object.net/twitter/duncancragg.json
}

Land

The Land type describes a physical area on a map:

{ UID: ...
  is: land
  title: "My Holding"
  area: 321.123
  shape: { lat: 54.106037, lon: -1.579163 }
         { lat: 54.106039, lon: -1.579231 }
         { lat: 54.106039, lon: -1.579232 }
         { lat: 54.106036, lon: -1.579162 }
}


Article

The Article type is used for blog entries, etc. It's partly based on Atom:

{ URL: http://duncan-cragg.org/blog/post/building-object-network/atom.cyr
  is: article
  title: "Building The Object Network"
  published: 2014-01-27T11:36:00Z
  updated: 2014-01-27T11:36:00Z
  web-view: http://duncan-cragg.org/blog/post/building-object-network/
  within: http://duncan-cragg.org/blog/atom.cyr
  tags: architecture declarative forest netmash cyrus object-network IoT
  text:
    "I've started another blog called [Building The Object Network][http://object-network.blogspot.co.uk/], about how I'm experimenting with Augmented Reality for the Internet of Things using the Object Network approach.",
    "So far I've been [blogging][http://object-network.blogspot.co.uk/2014/01/the-internet-of-3d-sensors-and-actuators.html] [every][http://object-network.blogspot.co.uk/2014/01/augmented-reality-and-magic.html] [day][http://object-network.blogspot.co.uk/2014/01/android-sensors-for-ar.html]."
    "Do subscribe! "
}

Article List

The Article List type is basically a feed, again based partly on Atom:

{ URL: http://duncan-cragg.org/blog/atom.cyr
  is: queryable article list
  title: "What Not How"
  sub-title: "Duncan Cragg on Declarative Architectures"
  author: http://duncan-cragg.org/blog/777-777.json
  id: http://duncan-cragg.org/blog/
  logo: http://duncan-cragg.org/favicon.gif
  icon: http://duncan-cragg.org/favicon.ico
  rights: "All content including photos and images by Duncan Cragg. Copyright (c) Duncan Cragg."
  generator: "Duncan Cragg's Django Blog"
  web-view: http://duncan-cragg.org/blog/
  atom: http://duncan-cragg.org/blog/atom/
  updated: 2014-01-27T11:36:00Z
  list: {
    is: article
    title: "Building The Object Network"
    published: 2014-01-27T11:36:00Z
    web-view: http://duncan-cragg.org/blog/post/building-object-network/
    More: http://duncan-cragg.org/blog/post/building-object-network/atom.cyr
  }{
    is: article
    title: "Cyrus in 2013"
    published: 2013-01-16T17:09:00Z
    web-view: http://duncan-cragg.org/blog/post/cyrus-2013/
    More: http://duncan-cragg.org/blog/post/cyrus-2013/atom.cyr
  }
}

It has a queryable "mixin", indicating that you can send a query..

Query

The Query Type can be notified to a queryable list, in this case, the above article list:

{ URL: http://
  is: article query
  querying: http://duncan-cragg.org/blog/atom.cyr
  match: {
    published: >= 2013-01-16T17:09:00Z
  }
}

It returns another, smaller article list than the one being queried, with a link to this query ("query").

Here is simple a rule that can run this query and return the response:

{ URL: http://
  is: article list rule
  Alerted: { is: article query  target: @ }
  list: maybe @Alerted:match
  latest-response: => {
    UID: new
    is: article list
    title: "Query results"
    source: @
    query: @Alerted
    list: @=list
    Notifying: @Alerted
  }
}

There are many query parameters that can be added. Here's a query that uses most of them:

{ URL: http://
  is: article query
  querying: http://duncan-cragg.org/blog/atom.cyr
  match: {
    tags: architecture cyrus
  }
  page-size: 4
  page-start: 2
  order-by: { published: > }
  inline: true
  results: tracking
}

Setting inline: true brings the results inline to the list, along with More: links to the individual result entries. The results: tracking parameter means that this response will be kept up-to-date as the matching results set changes.

This could return:

{ URL: http://duncan-cragg.org/..
  is: article list
  list: {
    is: article
    title: "Building The Object Network"
    published: 2014-01-27T11:36:00Z
    updated: 2014-01-27T11:36:00Z
    web-view: http://duncan-cragg.org/blog/post/building-object-network/
    within: http://duncan-cragg.org/blog/atom.cyr
    tags: architecture declarative forest netmash cyrus object-network IoT
    text:
      "I've started another blog called [Building The Object Network][http://object-network.blogspot.co.uk/], about how I'm experimenting with Augmented Reality for the Internet of Things using the Object Network approach.",
      "So far I've been [blogging][http://object-network.blogspot.co.uk/2014/01/the-internet-of-3d-sensors-and-actuators.html] [every][http://object-network.blogspot.co.uk/2014/01/augmented-reality-and-magic.html] [day][http://object-network.blogspot.co.uk/2014/01/android-sensors-for-ar.html]."
      "Do subscribe! "
    More: http://duncan-cragg.org/blog/post/building-object-network/atom.cyr
  }{
    is: article
    title: "Cyrus in 2013"
    published: 2013-01-16T17:09:00Z
    web-view: http://duncan-cragg.org/blog/post/cyrus-2013/
    :
    More: http://duncan-cragg.org/blog/post/cyrus-2013/atom.cyr
  }
}

GUI

The GUI type is a 2D layout with form elements can be defined as follows:

{ URL: ..
  is: gui
  title: "Page Title"
  view: { logo: http://..
          text: ".."
          xxx: { input: button label: "Push me" }
          yyy: { input: chooser label: "xxx:"
                 range: {
                   a: "A a"
                   b: "B b"
                   c: "C c"
                 }
          }
          zzz: { input: textfield label: ".." }
          mmm: { input: checkbox  label: ".." }
          mmm: { input: rating    label: ".." }
  }
}

Form

The Form type is sent back to the GUI object - when a client sees and renders a GUI with form elements then if there are input elements it can allow the user to create a form object:

{ URL: http://
  is: form
  gui: http://...
  user: http://...
  form: {
    pushed: xxx
    yyy: b
  }
}

Calculator example

Here is a simple calculator using the gui/form types:

{ UID: uid-7356-dfcc-2173-4525
  is: editable gui
  title: Calculator
  local: { acc: 0 num: 0 op: + }
  Rules:
    { is: gui rule  Alerted: { is: form }  local: { key: => @Alerted:form:pushed } }
    { is: gui rule  local: { key: /[0-9]/  num: => join (@. @local:key) } }
    { is: gui rule  local: { key: dp       num: => if (not @. contains .) then (join (@. .)) else @. } }
    { is: gui rule  local: { key: cl       num: => 0 }}
    { is: gui rule
      local: {
        key: /pl|mi|ti|di|eq/
        acc: => if (@local:num set) then (@. @local:op @local:num) else @.
        op: => { pl: +  mi: -  ti: ×  di: ÷  eq: + } select @local:key
        num: => #
      }
    }
    { is: gui rule  local: { key: cs  num: #  acc: => @. × -1  } }
    { is: gui rule  local: { key: cs  num: * => @. × -1 } }
    { is: gui rule  local: { key: ms  mem: => if (@local:num set) then @local:num else @local:acc } }
    { is: gui rule  local: { key: mr  num: => if (@local:mem set) then @local:mem else @. } }
    { is: gui rule  local: { key: * => # } view: { result: { value: => if (@local:num set) then @local:num else @local:acc }}}
  view: {
   result: { is: style direction: horizontal } { input: textfield  value: 0 }
   buttons:
     { style: { is: style direction: horizontal } 7: { input: button label: 7 }  8: { input: button label: 8 }  9: { input: button label: 9 } ti: { input: button label: × } cs: { input: button label: +/- } }
     { style: { is: style direction: horizontal } 4: { input: button label: 4 }  5: { input: button label: 5 }  6: { input: button label: 6 } di: { input: button label: ÷ } ms: { input: button label: MS  } }
     { style: { is: style direction: horizontal } 1: { input: button label: 1 }  2: { input: button label: 2 }  3: { input: button label: 3 } pl: { input: button label: + } mr: { input: button label: MR  } }
     { style: { is: style direction: horizontal } 0: { input: button label: 0 } dp: { input: button label: . } cl: { input: button label: C } mi: { input: button label: - } eq: { input: button label: =   } }
  }
}

Supplier

The Supplier type lists offerings (products, services, etc.) and links to outstanding order or application trackers of those offerings:

{ URL: http://coffee-shop.com/baristas
  is: coffee shop supplier
  products:
    { title: "Espresso"   More: /prod/esp1 }
    { title: "Cappuccino" More: /prod/cap2 }
  trackers:
    http://coffee-shop.com/track111
    http://coffee-shop.com/track110
    http://coffee-shop.com/track109
}

The trackers list may be kept in a separate list object. Lists of services are tagged services instead of products.

Product/Service

The Product type is linked to by a supplier and describes the products on offer:

{ URL: http://coffee-shop.com/prod/esp1
  is: coffee product gui
  supplier: http://coffee-shop.com/baristas
  title: "Espresso"
  description: "A shot of pure coffee"
  view: {
    shots:     { input: textfield label: "Shots" range: 1 .. 5 }
    ristretto: { input: checkbox  label: "Ristretto" }
  }
  price-text: "£1.50 single £2.50 double"
}

Being also a GUI type means it has a customisation gui allowing various fields to be added to the order.

There is also an equivalent service type, which is basically the same.

Order/Application

The Order type lists products requested from a supplier:

{ URL: http://my-orders.com/ordr321
  is: coffee order
  products: { product: http:/coffee-shop.com/prod/esp1  quantity: 1  shots: 2  ristretto: false }
            { product: http:/coffee-shop.com/prod/cap2  quantity: 3  shots: 1 }
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
  payment: http://my-orders.com/paym432
}

An order can have a list of product line items with link to product and quantity. The GUI form values are sent alongside the product link to which they refer.

There is also an equivalent application type, which is basically the same, but is used for requests for services or products where there is an assessment or eligibility aspect to supply of that service. It may have a services link instead of products, and has assessment instead of tracker.

An order may have invoice and delivery addresses as well as a general contact, which are links to contact objects:

{ URL: http://my-orders.com/ordr5422
  is: book order
  products: { product: /prod/book498239872  quantity: 1 }
  supplier: http://book-shop.com/
  tracker: http://book-shop.com/track1a40
  contact: http://my-orders.com/addr4332424
  invoice: http://my-orders.com/addr4332424
  delivery: http://my-orders.com/addr4332424
}

OrderTracker/Assessment

The OrderTracker type is owned by the supplier and tracks fulfilment of an order:

{ URL: http://coffee-shop.com/track111
  is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1  quantity: 1  shots: 1  ristretto: false }
  price: "£1.50"
  status: waiting { coffee: running  milk: frothing } priority-order
}

The status property may be complex: it may be a list of strings and/or sub-objects.

There is also an equivalent assessment type, which is used to evaluate and track applications rather than orders. It has a link to application instead of order, and may have a services link instead of products:

{ URL: http://barista-training.com/assess123123
  is: barista assessment
  application: http://barista-joe.com/application-to-pret
  contact: http://barista-joe.com/contact-card
  documents: http://visas.gov.uk/right-to-work/a7b3300.json http://barista-joe.com/CV.html
  services: { service: /barista-training/course32132  grade: master }
  price: "£150"
  status: { ristretto-quality: pass  frothy-ferns: 3.5  cleaning-up: under-evaluation }
}

Here, the contact link has been copied over from the application, but it can be found indirectly through the cached application link. There is also a link for supporting documentation that may be needed for an assessement.

Coffee Shop Example

There is a tradition in the distributed systems or integration community to use the example of ordering coffee to demonstrate your asynchronous system integration or distribution model.

It started with Gregor Hohpe's article about asynchronous messaging, then was continued by Jim Webber as "RESTbucks" to discuss his REST interpretation in an open forum and subsequently used to describe a refined version of the approach in the book by Jim and Ian Robinson.

Here's the Cyrus version. It's based on the Foreign Exchange ordering example I used in my FOREST paper, which in turn was actually a coffee ordering scenario in its first drafts.

-------------------------------------------------
{ URL: http://coffee-shop.com/baristas
  is: coffee shop supplier
  products:
    { title: "Espresso"   More: /prod/esp1 }
    { title: "Cappuccino" More: /prod/cap2 }
  trackers:
    http://coffee-shop.com/track110
    http://coffee-shop.com/track109
}
-------------------------------------------------
{ URL: http://coffee-shop.com/prod/esp1
  is: coffee product gui
  supplier: http://coffee-shop.com/baristas
  title: "Espresso"
  description: "A shot of pure coffee"
  view: {
    shots:     { input: textfield label: "Shots" range: 1 .. 5 }
    ristretto: { input: checkbox  label: "Ristretto" }
  }
  price-text: "£1.50 single £2.50 double"
}
-------------------------------------------------
{ URL: http://my-orders.com/ordr321
  is: coffee order
  products: { product: http://coffee-shop.com/prod/esp1 quantity: 1 shots: 1 ristretto: false }
  supplier: http://coffee-shop.com/baristas
  Notifying: http://coffee-shop.com/baristas
}

{ is: coffee shop supplier rule
  Alerted: { is: coffee order  supplier: @ }
  trackers: not { order: @Alerted } => @. with
    { UID: new
      is: coffee order-tracker
      order: @Alerted
      products: @Alerted:products
      price: ..
      status: waiting
      Notifying: => @. with @Alerted
    }
}
-------------------------------------------------
{ is: coffee shop supplier
  products:
    { title: "Espresso"   More: /prod/esp1 }
    { title: "Cappuccino" More: /prod/cap2 }
  trackers:
    http://coffee-shop.com/track111
    http://coffee-shop.com/track110
    http://coffee-shop.com/track109
}

{ URL: http://coffee-shop.com/track111
  is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 1 ristretto: false }
  price: "£1.50"
  status: waiting
  Notifying: http://my-orders.com/ordr321
}
-------------------------------------------------
{ is: coffee order
  products: { product: http://coffee-shop.com/prod/esp1 quantity: 1 shots: 2 ristretto: false }
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
  Notifying: http://coffee-shop.com/track111
}

{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£2.50"
  status: waiting
}
-------------------------------------------------
{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£2.50"
  status: filled
}
-------------------------------------------------
{ is: coffee order
  products: { product: http://coffee-shop.com/prod/cap2 quantity: 1 shots: 2 }
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
}

{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£2.50"
  status: filled not-as-ordered
}
-------------------------------------------------
{ is: coffee order
  products: cancelled
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
}

{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£0.00"
  status: cancelled
}
-------------------------------------------------
{ is: coffee order
  products: { product: http://coffee-shop.com/prod/esp1 quantity: 1 shots: 2 ristretto: false }
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
}

{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£2.50"
  status: filled
}
-------------------------------------------------
{ is: coffee order
  products: { product: http://coffee-shop.com/prod/esp1 quantity: 1 shots: 2 ristretto: false }
  supplier: http://coffee-shop.com/baristas
  tracker: http://coffee-shop.com/track111
  payment: http://my-orders.com/paym432
}
-------------------------------------------------
{ URL: http://my-orders.com/paym432
  is: payment
  invoice: http://coffee-shop.com/track111
  order: http://my-orders.com/ordr321
  amount: £2.50
  account: { .. }
}
-------------------------------------------------
{ is: coffee order-tracker
  order: http://my-orders.com/ordr321
  products: { product: /prod/esp1 quantity: 1 shots: 2 ristretto: false }
  price: "£2.50"
  status: paid
  payment: http://my-orders.com/paym432
}
-------------------------------------------------

3D Objects

3D Object type :

{ URL: http://../uid-7794-3aa8-2192-7a60
  is: 3d mesh
  title: Avatar
  rotation: 0 45 0
  scale: 1 1 1
  vertices:
    (  1  0  0 ) (  1  0  1 ) (  0  0  1 ) (  0  0  0 )
    (  1  1  0 ) (  1  1  1 ) (  0  1  1 ) (  0  1  0 )
  texturepoints: ( 0.0 0.0 ) ( 1.0 0.0 ) ( 1.0 1.0 ) ( 0.0 1.0 )
  normals: ( -1.0  0.0  0.0 ) ( 1.0 0.0 0.0 )
           (  0.0 -1.0  0.0 ) ( 0.0 1.0 0.0 )
           (  0.0  0.0 -1.0 ) ( 0.0 0.0 1.0 )
  faces:
    ( 5/1/5 1/2/5 4/3/5 ) ( 5/1/5 4/3/5 8/4/5 ) ( 3/1/1 7/2/1 8/3/1 )
    ( 3/1/1 8/3/1 4/4/1 ) ( 2/1/6 6/2/6 3/4/6 ) ( 6/2/6 7/3/6 3/4/6 )
    ( 1/1/2 5/2/2 2/4/2 ) ( 5/2/2 6/3/2 2/4/2 ) ( 5/1/4 8/2/4 6/4/4 )
    ( 8/2/4 7/3/4 6/4/4 ) ( 1/1/3 2/2/3 3/3/3 ) ( 1/1/3 3/3/3 4/4/3 )
  textures: http://fc08.deviantart.net/fs51/i/2009/284/5/e/IMVU_eye_texture_by_lilylisete.png
  vertex-shader: http://10.0.2.2:8081/o/uid-ff5d-1ef4-cfa5-5f92.json
  fragment-shader: http://10.0.2.2:8081/o/uid-1ff8-59e9-6dac-9b56.json
}

Here is how shaders are published:

{ is: 3d vertex shader string list
  title: "Dynamic Phong Vertex Shader"
  list:
    "uniform mat4 mvpm, mvvm;"
    "attribute vec4 pos;"
    "attribute vec2 tex;"
    "attribute vec3 nor;"
    "varying vec3 mvvp;"
    "varying vec2 texturePt;"
    "varying vec3 mvvn;"
    "void main(){"
      "texturePt = tex;"
      "mvvp = vec3(mvvm*pos);"
      "mvvn = vec3(mvvm*vec4(nor,0.0));"
      "gl_Position = mvpm*pos;"
    "}"
}

User

The User Type represents the live, dynamic user that is active in a mobile device, etc:

{ URL: http://
  is: user
  saying: " .. "
  within: ..
  position: 0.0 0.0 0.0
  avatar: http://
  location: { lat: 54.106037, lon: -1.579163 }
  contact: http://
  homeusers: http://
  private: {
    viewing: http://
    editing: http://
    viewas: gui
    links: ..
    links-around:
    history:  ..
    contacts: ..
    responses: { }
    position: { }
    orientation: { }
  }
}

Users may have current status ("saying"), a virtual place they're "within", a position in that place, an avatar object, a GPS location, a contact object, etc. The "homeusers" link is to a serverside "home" to which the user's state can be pushed, since users will typically be run asymmetrically, without the ability to be directly published.

The "private" section is all content that won't be pushed or published either because it's private data or because it's changing too fast and is too low-level for public use - it should be stripped off and kept only inside the mobile device. It includes what the user is currently viewing, how they are viewing it (as a GUI, a map or raw data), their viewing history, contacts list, orientation of the phone, etc.

Internet of Things example

This is the code from my 60 Days of Things project.

{ UID: uid-41b6-5f8f-f143-b30d
  Class: cyrus.types.PresenceTracker
  is: place 3d mesh editable
  title: "Room of Things"
  sub-items: { item: uid-52e0-e5c3-0ed1-6ed3 position: 15 1 10 }
  scale: 20 20 20
  vertices: ( 1 0 0 ) ( 1 0 1 ) ( 0 0 1 ) ( 0 0 0 )
  texturepoints: ( 0 0 ) ( 5 0 ) ( 5 5 ) ( 0 5 )
  normals: ( 0 1 0 )
  faces: ( 2/3/1 1/2/1 4/1/1 ) ( 2/3/1 4/1/1 3/4/1 )
  textures: http://www.textures123.com/free-texture/sand/sand-texture4.jpg
  vertex-shader: uid-ff5d-1ef4-cfa5-5f92
  fragment-shader: uid-1ff8-59e9-6dac-9b56
  x: 7
}

This is the room object where it all happens. It has a link to the following light sensor:

{ UID: uid-52e0-e5c3-0ed1-6ed3
  is: 3d cuboid editable light-sensor
  title: "Light Level"
  scale: 0.3 0.3 0.3
  within: uid-41b6-5f8f-f143-b30d
  textures: http://www.textures123.com/free-texture/sand/sand-texture4.jpg
  light-level: 100
}

There is a light on another server that links to the room/place object it is within:

{ Rules: http://netmash.net/o/uid-16bd-140a-8862-41cd.cyr
         http://netmash.net/o/uid-6f1a-4c7c-d111-2679.cyr
         http://netmash.net/o/uid-9011-94df-9feb-e3c2.cyr
         http://netmash.net/o/uid-2f18-945a-c460-9bd7.cyr
  is: 3d cuboid editable
  title: Light
  rotation: 45 45 45
  scale: 1 1 1
  light: 1 1 1
  position: 0 0 0
  within: http://10.0.2.2:8081/o/uid-41b6-5f8f-f143-b30d.json
}

It has four rules. First, how to set its colour on touch by the user:

{ URL: http://netmash.net/o/uid-16bd-140a-8862-41cd.cyr
  is: 3d rule
  when: "touched, set light colour"
  Alerted: { is: user  touching: { item: @ } }
  light: => @Alerted:touching:position * 1.4
}

Next, telling the room/place that it's here on start-up/discovery:

{ URL: http://netmash.net/o/uid-6f1a-4c7c-d111-2679.cyr
  is: 3d rule
  when: "starting, notify place within"
  Notifying: => @. with @within
}

Getting a link to the light level sensor in the room, if any:

{ URL: http://netmash.net/o/uid-9011-94df-9feb-e3c2.cyr
  is: 3d rule
  when: "starting, get light-sensor"
  within: { sub-items: { item: { is: light-sensor } } }
  light-sensor: # => @=within:sub-items:item
}

And responding to the light level:


{ URL: http://netmash.net/o/uid-2f18-945a-c460-9bd7.cyr
  is: 3d rule
  when: "it gets dark, turn light on"
  light-sensor: { light-level: < 100 }
  light: => 1 1 1
}

This is a sketch of how to set a light brightness according to a dimmer object:

{ UID: uid-1
  is: light
  rules: uid-3
  colour: 1 1 0
  light: 0.5.0.5 0
  dimmer: http://../uid-2
}

{ UID: uid-2
  is: dimmer
  setting: 0.5
}

{ UID: uid-3
  is: light rule
  light: => @color * @dimmer:setting
}

Editable

The Editable type is a "mixin" type that means this object is happy to accept Cyrus rules to update it:

{ URL: http://..
  Version: 33
  is: editable thing
  thing-prop: a
}

Here is what a typical edit rule may look like:

{ is: editable rule
  when: edited
  editable: http://..
  user: http://..
  : { Version: 33 } => as-is {
    is: editable thing
    thing-prop: b
  }
}

This rewrites the whole object (matching the single colon) matching version 33 to the given right-hand side. Of course, you could have a rule that rewrites just part of the target.

old stuff

Duncan Cragg, 2014

Contact me and/or subscribe to my blog and/or follow me on Twitter.

[E217]