<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>RubyAgent</title>
	<atom:link href="http://www.rubyagent.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.rubyagent.com</link>
	<description>Ruby on Blackboard</description>
	<pubDate>Wed, 09 Apr 2008 22:02:06 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Scheduling of Ruby Agents using Cron</title>
		<link>http://www.rubyagent.com/2008/02/scheduling-of-ruby-agents-using-cron/</link>
		<comments>http://www.rubyagent.com/2008/02/scheduling-of-ruby-agents-using-cron/#comments</comments>
		<pubDate>Thu, 07 Feb 2008 21:15:15 +0000</pubDate>
		<dc:creator>viz</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[cron]]></category>

		<category><![CDATA[linux]]></category>

		<category><![CDATA[ruby]]></category>

		<category><![CDATA[scheduling]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=19</guid>
		<description><![CDATA[One of the main principles of agent-oriented modeling is agent&#8217;s proactivness - living and acting continuously on its own. Technically, this means that the piece of code is running in a kind of loop receiving messages, acting upon them and sending out other messages. This is the heartbeat of each agent.
The most naive approach is [...]]]></description>
			<content:encoded><![CDATA[<p>One of the main principles of agent-oriented modeling is agent&#8217;s <em>proactivness</em> - living and acting continuously on its own. Technically, this means that the piece of code is running in a kind of loop receiving messages, acting upon them and sending out other messages. This is the heartbeat of each agent.</p>
<p>The most naive approach is to run a piece of code as a separate process (or thread). The code spins a loop where it receives messages, dispatches them and sleeps for some time. You could see such a pattern in some of the previous posts (<a href="?p=15"> Pattern: Agent Life Cycle</a>).</p>
<p>Another approach is to use scheduling. An agents schedules its next activities to certain times. This approach is usually advantageous for long- and sparsely-running agents. A good example can be monitoring agent, a news-sending agent, or even plain-old UNIX maintenance scripts, etc..<br />
Here, again, we can choose from two methods of scheduling:</p>
<ol>
<li>The agent determines only the very next time of its execution.</li>
<li>The agents uses a full static schedule - execution plan.</li>
</ol>
<p>The former method is very dynamic, flexible allowing the agent adopt its behavior immediately. However, it can be vulnerable to possible errors. An error can cause the agent won&#8217;t register anymore. In fact it becomes dead. The later method is predictable and suitable for static environments.</p>
<p>In the rest of this post I demonstrate how easy it can be to operate a cron driven &#8220;agent&#8221; directly from your Ruby code.</p>
<h4>Cron Scheduling</h4>
<p>You can decide to use Ruby native scheduler (like  <a href="http://rufus.rubyforge.org/rufus-scheduler/">rufus-scheduler</a>), or rely on an external service (like Unix Cron, or other dedicated middleware). This time I show you how to engage with Unix Cron scheduling (next time I tell you more about other schedulers.) Well, for simple cases you can edit cron manually, i.e. install your schedule using crontab. But for more complex and dynamic cases this is a pain in the ass. Imagine you have dozens (or hundreds) of autonomous agents running on your system, or you have very frequent schedule modifications. The <a href="http://cronedit.rubyforge.org/">CronEdit</a> library help us out here.<br />
Install it as a gem:</p>
<pre lang="bash">sudo gem install cronedit</pre>
<p>or get it from its <a href="http://rubyforge.org/projects/cronedit">project home</a>.</p>
<p>CronEdit library associates each cron entry with an id. This makes it uniquely manipulable and not interfering with other entries. It is because the rest of the actual crontab is left unchanged. So you can manipulate the crontab as  comfortable as it was a Hash. Your cron entry definition itself can have a standard cron text format, or alternatively you can use Hash notation. Let&#8217;s look at few simple examples.</p>
<p><em><strong>Simple operations using class methods </strong></em></p>
<pre lang="ruby">
require 'cronedit'
include CronEdit
Crontab.Add  :agent1, '5,35 0-23/2 * * * echo 123'
Crontab.Add  :agent2, {:minute=&gt;5, :command=&gt;'ruby /agents/agent.rb 42'}
Crontab.Remove 'agent1', 'agent2'</pre>
<p>The first line registers a cron entry in standard text notation under id &#8216;agent1 &#8216;. The second line registers entry &#8216;agent2&#8242; using Hash notation. The last line deletes both entries. The changes are effective immediately. You can list all actual entries by:</p>
<pre lang="ruby">
p Crontab.List</pre>
<p><strong><em>Batch/transactional updates</em></strong><br />
In case you need to do more changes at once use the following approach</p>
<pre lang="ruby">
cm = CronEdit::Crontab.new
cm.add 'agent1', '5,35 0-23/2 * * * echo agent1'...
cm.add 'agent2', {:minute=&gt;5, :command=&gt;'echo 42'}
cm.remove 'agentKiller'
cm.commit</pre>
<p>Inversely, you can also rollback the operations.</p>
<p><strong><em>Bulk update/removal using file definitions</em></strong><br />
In more complex scenarios (communities of agenst) you often need to manipulate more agents at once with their definitions in files. Imagine you have a crowd of news-gathering agents and mail-analysis agents. The cron definitions for these groups are stored as files (previously generated by CronEdit)</p>
<pre lang="ruby">
fc = FileCrontab.new '/agents/news-gathering.cron'
Crontab.Merge fc...
Crontab.Subtract fc</pre>
<p>The first line uses FileCrontab to read the cron definition of all news-gathering agents. The file crontab is merged in to the actual system crontab on the next line. Similarly the definitions can be &#8216;unloaded&#8217; using &#8217;subtract&#8217; method.</p>
<p>The library allows you do even more (e.g. when you definitions are in DB; combining multiple definitions)<br />
See more <a href="http://cronedit.rubyforge.org/">examples and documentation</a>.</p>
<p>In the next posts I present another simple piece of the infrastructure helpful for this type of agents.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2008/02/scheduling-of-ruby-agents-using-cron/feed/</wfw:commentRss>
		</item>
		<item>
		<title>New Author</title>
		<link>http://www.rubyagent.com/2008/02/new-author/</link>
		<comments>http://www.rubyagent.com/2008/02/new-author/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 08:52:47 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[author]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=18</guid>
		<description><![CDATA[I would like to welcome a new author, a good friend of mine, Ruby and agent-based systems fan: Viktor Zigo (viz).
His first post will be about scheduling agents.
Welcome :)
]]></description>
			<content:encoded><![CDATA[<p>I would like to welcome a new author, a good friend of mine, Ruby and agent-based systems fan: <a href="http://alephzarro.com">Viktor Zigo</a> (viz).<br />
His first post will be about scheduling agents.<br />
Welcome :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2008/02/new-author/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pattern: Shutdown Flag</title>
		<link>http://www.rubyagent.com/2007/12/pattern-shutdown-flag/</link>
		<comments>http://www.rubyagent.com/2007/12/pattern-shutdown-flag/#comments</comments>
		<pubDate>Tue, 18 Dec 2007 00:19:13 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[boolean flag]]></category>

		<category><![CDATA[life cycle]]></category>

		<category><![CDATA[pattern]]></category>

		<category><![CDATA[shutdown flag]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=17</guid>
		<description><![CDATA[Problem: An agent should consider a shutdown flag presence.
Solution: The solution is to use a modified Boolean Flag Pattern, where the flag specific operation is to break the loop for reading an n-tuple, i.e. the Agent Life Cycle pattern.
(life cycle, boolean flag and shutdown flag patterns)

loop do
  begin
    read or take [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Problem:</strong> An agent should consider a shutdown flag presence.</p>
<p><strong>Solution:</strong> The solution is to use a modified Boolean Flag Pattern, where the flag specific operation is to break the loop for reading an n-tuple, i.e. the Agent Life Cycle pattern.</p>
<p>(<span style="color: blue;">life cycle</span>, <span style="color: green;">boolean flag</span> and <span style="color: #008080;">shutdown flag</span> patterns)</p>
<pre style="color: blue;">
loop do
  begin
    read or take n-tuple with timeout t1
</pre>
<pre style="color: green;">
  rescue Rinda::RequestExpiredError

    begin
      read the shutdown flag with timeout t2
</pre>
<pre style="color: #008080;">
      break # stop listening for the n-tuple
</pre>
<pre style="color: green;">
    rescue Rinda::RequestExpiredError
</pre>
<pre style="color: #008080;">
      # ignore a situation when there is no shutdown flag
</pre>
<pre style="color: green;">
    end

    next # repeat the loop

  end
</pre>
<pre style="color: blue;">
  process n-tuple
end
</pre>
<p><strong>Example:</strong></p>
<p>(<span style="color: blue;">life cycle</span>, <span style="color: green;">boolean flag</span> and <span style="color: #008080;">shutdown flag</span> patterns)</p>
<pre style="color: blue;">
loop do
  begin
    t = ts.take [:plus, nil, nil], 10
</pre>
<pre style="color: green;">
  rescue Rinda::RequestExpiredError

    begin
      ts.read [:end], 1
</pre>
<pre style="color: #008080;">
      break # stop listening for the n-tuple
</pre>
<pre style="color: green;">
    rescue Rinda::RequestExpiredError
</pre>
<pre style="color: #008080;">
      # ignore a situation when there is no shutdown flag
</pre>
<pre style="color: green;">
    end

    next # repeat the loop

  end
</pre>
<pre style="color: blue;">
  res = t[1] + t[2]
  ts.write [:result, res]
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/12/pattern-shutdown-flag/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pattern: Boolean Flag</title>
		<link>http://www.rubyagent.com/2007/12/pattern-boolean-flag/</link>
		<comments>http://www.rubyagent.com/2007/12/pattern-boolean-flag/#comments</comments>
		<pubDate>Tue, 18 Dec 2007 00:06:57 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[boolean flag]]></category>

		<category><![CDATA[life cycle]]></category>

		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=16</guid>
		<description><![CDATA[Problem: An agent should consider a flag presence.
Solution: The solution is to set a timeout for a read or take operation, where the timeout value specifies how often a flag appearance should be checked, and if the flag is presented to perform the flag specific operation.
The Agent Life Cycle pattern is, of course, used too.
(life [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Problem:</strong> An agent should consider a flag presence.</p>
<p><strong>Solution:</strong> The solution is to set a timeout for a read or take operation, where the timeout value specifies how often a flag appearance should be checked, and if the flag is presented to perform the flag specific operation.</p>
<p>The Agent Life Cycle pattern is, of course, used too.</p>
<p>(<span style="color: blue;">life cycle</span> and <span style="color: green;">boolean flag</span> patterns)</p>
<pre style="color: blue;">
loop do
  begin
    read or take n-tuple with timeout t1
</pre>
<pre style="color: green;">
  rescue Rinda::RequestExpiredError

    begin
      read the flag n-tuple with timeout t2
      perform a flag specific operation
    rescue Rinda::RequestExpiredError
      perform an operation when the flag is not set
    end

    next # repeat the loop

  end
</pre>
<pre style="color: blue;">
  process n-tuple
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/12/pattern-boolean-flag/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Pattern: Agent Life Cycle</title>
		<link>http://www.rubyagent.com/2007/12/pattern-agent-life-cycle/</link>
		<comments>http://www.rubyagent.com/2007/12/pattern-agent-life-cycle/#comments</comments>
		<pubDate>Mon, 17 Dec 2007 23:58:07 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[life cycle]]></category>

		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=15</guid>
		<description><![CDATA[Problem: An agent should be able to check the blackboard for an n-tuple and to process the obtained n-tuple. (It is a trivial pattern.)
Solution: The solution is to perform operation read or take in a loop.

loop do
  read or take n-tuple

  process n-tuple
end

Example:

loop do
  t = ts.take [:plus, nil, nil]

  res [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Problem:</strong> An agent should be able to check the blackboard for an n-tuple and to process the obtained n-tuple. (It is a trivial pattern.)</p>
<p><strong>Solution:</strong> The solution is to perform operation read or take in a loop.</p>
<pre style="color: blue;">
loop do
  read or take n-tuple

  process n-tuple
end
</pre>
<p><strong>Example:</strong></p>
<pre style="color: blue;">
loop do
  t = ts.take [:plus, nil, nil]

  res = t[1] + t[2]
  ts.write [:result, res]
end
</pre>
<p><strong>Comments:</strong><br />
The method process should execute agent&#8217;s duty :), there is only questionable, if it should:</p>
<ul>
<li>start a new thread, to process the loaded n-tuple, and immediately listen for a next n-tuple</li>
<li>or it should process the loaded n-tuple, and when the processing is finished, to start listening for a next n-tuple.</li>
</ul>
<p>I would prefer the second way - it is more agent-like, it is not mixing threads and agents concepts (including managing agents vs managing threads) - if you would like to process more n-tuples in parallel, simply start another agent instance.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/12/pattern-agent-life-cycle/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Access Blackborad With Timeout</title>
		<link>http://www.rubyagent.com/2007/12/access-blackborad-with-timeout/</link>
		<comments>http://www.rubyagent.com/2007/12/access-blackborad-with-timeout/#comments</comments>
		<pubDate>Fri, 14 Dec 2007 09:34:07 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[Introduction]]></category>

		<category><![CDATA[Rinda]]></category>

		<category><![CDATA[blackboard]]></category>

		<category><![CDATA[timeout]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=11</guid>
		<description><![CDATA[Operations that access a blackboard to retrieve information, i.e. operations read and take, have a second parameter that defines how long should this operation wait until there will be a matching n-tuple or, simply, timeout. A value of the parameter specifies number of second.
Example:

To read a tuple and if there is no such tuple, to [...]]]></description>
			<content:encoded><![CDATA[<p>Operations that access a blackboard to retrieve information, i.e. operations <strong>read</strong> and <strong>take</strong>, have a second parameter that defines how long should this operation wait until there will be a matching n-tuple or, simply, timeout. A value of the parameter specifies number of second.</p>
<p>Example:</p>
<ul>
<li>To read a tuple and if there is no such tuple, to wait 4 seconds for it:
<pre lang="Ruby">
ts.read [nil, nil], 4
</pre>
</li>
<li>Or to take a tuple and if there is no such tuple, to wait 1 minute for it:
<pre lang="Ruby">
ts.take [nil, nil], 60
</pre>
</li>
</ul>
<p>There are two special values that you may use as a timeout value:</p>
<ul>
<li><strong>0 (zero)</strong> - an operation would not wait at all. It is useful for checking, if a n-tuple is stored in the blackboard or not.</li>
<li><strong>nil</strong> - an operation would wait endlessly. Of course, there is not difference if you would call an operation without a specified timeout value or with nil. <br />
Actually, to be more precise, an operation would wait 2<sup>31</sup> - 1 seconds, that is approximately 30 years. ;)
</li>
</ul>
<blockquote><p>
But what would happen, if we specify a timeout value and an n-tuple would not appear on the blackboard in the specified time(out)? <br />
Rinda throws the <strong>Rinda::RequestExpiredError</strong> exception.
</p></blockquote>
<p>The handling exceptions in Ruby is very comfortable (esp. with the command retry). An example follows, where a tuple is taken with a timeout 5 seconds. This allows to inform an user about the state, that the application is still waiting for a message:</p>
<pre lang="Ruby">
puts "Waiting for a message."
begin
  t = ts.take [:message, nil], 5
rescue Rinda::RequestExpiredError
  puts &#8220;Still waiting for a message.&#8221;
  retry
end
</pre>
<p>The timeout functionality allows to:</p>
<ul>
<li>create a responsiveness application - to inform other components or users about its state (e.g. waiting for a message - processing a message).</li>
<li>end an application normally - to break waiting for a n-tuple every so often and check if the application should end.</li>
<li>check for different n-tuples - it is possible to wait in deferent intervals for different n-tuples. Of course, a better solution is to create for each n-tuple an own thread that performs a blackboard access operation for this particular n-tuple.</li>
<li>create an application that does not access a blackboard all the time (e.g. only every hour for 1 minute).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/12/access-blackborad-with-timeout/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Simple Example - Calculator Agent</title>
		<link>http://www.rubyagent.com/2007/05/simple-example-calculator-agent/</link>
		<comments>http://www.rubyagent.com/2007/05/simple-example-calculator-agent/#comments</comments>
		<pubDate>Sun, 20 May 2007 13:55:59 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[Example]]></category>

		<category><![CDATA[Rinda]]></category>

		<category><![CDATA[take]]></category>

		<category><![CDATA[write]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=7</guid>
		<description><![CDATA[Now, we have enough knowledge to create a simple example: a calculator.
The example shows how to:

Create an agent.
Locate the blackboard.
Write a tuple (a calculator operation).
Take a tuple (a calculator operation result).
Differentiate between different operations (plus and minus).
Handle a simple ID.

The calculator agent will be able to handle two kinds of operations: plus and minus. It [...]]]></description>
			<content:encoded><![CDATA[<p>Now, we have enough knowledge to create a simple example: a calculator.</p>
<p>The example shows how to:</p>
<ul>
<li>Create an agent.</li>
<li>Locate the blackboard.</li>
<li>Write a tuple (a calculator operation).</li>
<li>Take a tuple (a calculator operation result).</li>
<li>Differentiate between different operations (plus and minus).</li>
<li>Handle a simple ID.</li>
</ul>
<p>The calculator agent will be able to handle two kinds of operations: <em>plus</em> and <em>minus</em>. It will receive an <strong>operation request tuple</strong>, where one item will be an operation identifier (to handle two operations) and two items with numerical values (to transmit values).<br />
The agent will produce a <strong>result tuple</strong>, where one item will be a numerical value (to transmit back a result value).<br />
To track a result, each operation request tuple will have an ID, that will be inserted back into a result tuple.</p>
<p>To sum up, there will be two tuple types:</p>
<ul>
<li>operation request <code>[:calculator, id, operation, a, b]</code>, e.g.<br />
<code>[:calculator, id, :plus, 1, 2]</code> or <code>[:calculator, id, :minus, 6, 2]</code>.</li>
<p><br/></p>
<li>result <code>[:result, id, value]</code>, e.g.<br />
<code>[:result, id, 4]</code>.</li>
</ul>
<p>To run this example, we will need three files: <code>rinda.rb</code> to start the environment, <code>calculator.rb</code> the calculator agent and <code>client.rb</code> to send requests and display results.</p>
<p><br/></p>
<p>The calculator agent source code, <a href="/files/simple_calculator.zip"><code>calculator.rb</code></a>:</p>
<pre lang="ruby">
require 'rinda/ring'
require 'rinda/tuplespace'

# A simple calculator example.
#
class SimpleCalculator

  def plus(a, b)
    a + b
  end

  def minus(a, b)
    a - b
  end

  def main
    DRb.start_service
    ts = Rinda::RingFinger.primary

    loop do
      t = ts.take [:calculator, nil, nil, nil, nil] # take an operation request

      # assign values
      id = t[1]
      operation = t[2]
      arg1 = t[3]
      arg2 = t[4]

      puts &#8220;Calculator recived operation ##{id} #{operation} with arguments #{arg1} and #{arg2}&#8221;

      res = operation == &#8216;plus&#8217; ? plus(arg1, arg2) : minus(arg1, arg2) # perform the received operation
      #sleep 1 # to pretend that an operation takes longer

      ts.write [:result, id, res] # send a result back
    end
  end
end

SimpleCalculator.new.main
</pre>
<p><br/></p>
<p>And the client source code, <a href="/files/simple_calculator.zip"><code>client.rb</code></a>:</p>
<pre lang="ruby">
require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

t1 = Time.now #the start time

# sending operation requests

id = 1 # the ID
for i in (1..5) # plus operations
  puts "Sending operation ##{id} plus with arguments #{i} and 1"
  ts.write [:calculator, id, :plus, i, 1]
  id += 1 # an unique ID value
end
for i in (5..9) # minus operations
  puts &#8220;Sending operation ##{id} minus with arguments #{i} and 1&#8243;
  ts.write [:calculator, id, :minus, i, 1]
  id += 1 # an unique ID value
end

puts &#8220;Waiting for results&#8230;&#8221;

# receiving results

i = 1
loop do
  t = ts.take [:result, nil, nil], 2
  puts &#8220;Result ##{t[1]} = #{t[2]}&#8221;
  i += 1
  break if i > 10 # 10 request were sent
end

t2 = Time.now # the end time
puts &#8220;The operation took #{t2 - t1} seconds.&#8221;
</pre>
<p>See a <a href="http://www.rubyagent.com/videos/simple_calculator.ogg">screencast <img align="top" src="/images/screencast.gif" title="Simple calculator agent screencast [.ogg]" alt="Simple calculator agent screencast [.ogg]" /></a></p>
<p>To start the example, firstly start the environment <code>ruby rinda.rb</code> and then start the calculator agent <code>ruby calculator.rb</code>. Each execution of the client, <code>ruby client.rb</code>, will produce 10 operation requests that will be processed by the agent. The agent will produce 10 results, that will be read by the client.</p>
<p>There is a lot of log messages, so you can easily see when an agent instance received a request, when it send a result and when a client send a request and received a result. With the <em>#id</em> part of a log message you can track particular communication parts.</p>
<p>Execution time should be very short, approx. 0.06 seconds.<br />
<br/><br />
Let&#8217;s imagine that an operation processing would take longer, e.g. 1 second. Uncomment the 32<sup>nd</sup> line in the agent source code <code>calculator.rb</code> and restart all parts of the example (rinda.rb and calculator.rb).<br />
Execute the client and the execution time will be, as expected, 10.06 seconds.<br />
<br/><br />
And now, to show power of a parallel processing in a <em>multi</em>-agent system, start another calculator agent&#8230;</p>
<p>The logs of the started calculator agent instances show that the processing load was nicely shared between the agents.</p>
<p>The result? A half of time (of course), approx. 5.04 seconds.</p>
<p>I like it :)</p>
<p><br/></p>
<p>Files to download: <a href="/files/simple_calculator.zip"><code>simple_calculator.zip</code></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/05/simple-example-calculator-agent/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Read Message On Blackboard</title>
		<link>http://www.rubyagent.com/2007/05/read-message-on-blackboard/</link>
		<comments>http://www.rubyagent.com/2007/05/read-message-on-blackboard/#comments</comments>
		<pubDate>Fri, 18 May 2007 10:12:13 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[Howto]]></category>

		<category><![CDATA[Rinda]]></category>

		<category><![CDATA[blackboard]]></category>

		<category><![CDATA[read]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=14</guid>
		<description><![CDATA[To finish the overview of the backboard operations, let&#8217;s show how to use the read operation. It only checks, if a blackboard contains a wanted tuple (in the previous posts I used the term message, but now we are more experienced :).
The following functionalities will be shown:

Creation of an agent.
Locating the blackboard.
Read a message.

The agent [...]]]></description>
			<content:encoded><![CDATA[<p>To finish the overview of the backboard operations, let&#8217;s show how to use the <strong>read</strong> operation. It only checks, if a blackboard contains a wanted tuple (in the previous posts I used the term message, but now we are more experienced :).</p>
<p>The following functionalities will be shown:</p>
<ul>
<li>Creation of an agent.</li>
<li>Locating the blackboard.</li>
<li>Read a message.</li>
</ul>
<p>The agent source code is stored in the <code>read.rb</code> file:</p>
<pre lang="Ruby">
require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

result = ts.read [:message, nil], 0

puts &#8220;[0]: #{result[0]}&#8221;
puts &#8220;[1]: #{result[1]}&#8221;
</pre>
<p><br/></p>
<p>See a <a href="http://www.rubyagent.com/videos/read_msg_bb.ogg">screencast <img align="top" src="/images/screencast.gif" title="Read message on blackboard screencast [.ogg]" alt="Read message on blackboard screencast [.ogg]" /></a>.</p>
<p>Firstly, start the <code>rinda.rb</code> code (for more details <a href="http://www.rubyagent.com/?p=8">see the post about starting multi-agent system environment</a>), then, in a separate console, start the <code>write.rb</code> (for more details <a href="http://www.rubyagent.com/?p=10">see the post about writing a message to the blackboard</a>) and finally, in a separate console or in the same console where you started the write.rb file, type:</p>
<pre lang="bash">
ruby read.rb
</pre>
<p>The agent connects to the blackboard, reads a tuple and shows two lines:</p>
<pre lang="text">
[0]: message
[1]: Hi there!
</pre>
<p>Of course, you could repeat this step any number of times, because this operation only checks if a tuple is there.</p>
<p><br/></p>
<p>Files to download: <a href="/files/starting_mase/rinda.rb"><code>rinda.rb</code></a>, <a href="/files/write_msg_bb/write.rb"><code>write.rb</code></a> and <a href="/files/read_msg_bb/read.rb"><code>read.rb</code></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/05/read-message-on-blackboard/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Message and Tuple</title>
		<link>http://www.rubyagent.com/2007/04/message-and-tuple/</link>
		<comments>http://www.rubyagent.com/2007/04/message-and-tuple/#comments</comments>
		<pubDate>Sat, 31 Mar 2007 23:51:07 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[Howto]]></category>

		<category><![CDATA[Introduction]]></category>

		<category><![CDATA[message]]></category>

		<category><![CDATA[take]]></category>

		<category><![CDATA[tuple]]></category>

		<category><![CDATA[write]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=13</guid>
		<description><![CDATA[In the last posts a term message was used. In the Rinda documentation you would not probably find this term; it is called more accurately: tuple.

What is a tuple?

[1, 2] is a tuple
[:message, 'Hi there!'] is a tuple
['Hi there!', :message] is also a tuple
[:result, 42, 'John', 'Susanne', 'London'] is a tuple
[:clock, Time.new] is a tuple [...]]]></description>
			<content:encoded><![CDATA[<p>In the last posts a term <strong>message</strong> was used. In the Rinda documentation you would not probably find this term; it is called more accurately: <strong>tuple</strong>.</p>
<p><br/></p>
<p>What is a tuple?</p>
<ul>
<li>[1, 2] is a tuple</li>
<li>[:message, 'Hi there!'] is a tuple</li>
<li>['Hi there!', :message] is also a tuple</li>
<li>[:result, 42, 'John', 'Susanne', 'London'] is a tuple</li>
<li>[:clock, Time.new] is a tuple too</li>
<li>[:service, CalculatorService.new(1, true) is a tuple</li>
</ul>
<p>Tuple is an ordered list of elements [<a href="http://en.wikipedia.org/wiki/Tuple">wikipedia</a>].</p>
<p><br/></p>
<blockquote><p>
A blackboard is a place to share tuples; agents are writing, reading and taking tuples.
</p></blockquote>
<p>If you have a simple system, where agents are using only one kind of messages, it is enough to use a single, e.g. <code>[1]</code>, <code>['Hello']</code>. But what to do, if your system requires to differentiate more types of messages? <em>Well, there is no problem with writing different types of messages, but there is a problem how to find the correct one to read or take it.</em></p>
<p>Basically there are two possibilities:</p>
<ul>
<li>Every type of a message has different number of elements. The <strong>number of elements</strong> is the distinguishing sign.
<p>Example: <code>[1]</code> is similar to <code>[2]</code> or <code>['Hello']</code>, but it is different then <code>[3, 'Hello']</code>.</li>
<li>One of the parameters is an <strong>identifier</strong>. The <strong>number of elements</strong> and an <strong>identifier</strong> are the distinguishing signs.
<p>Example: <code>[:request, 1, 2]</code> is similar to <code>[:request, 24, 'John']</code>, but it is different to <code>[:result, 42, 'London']</code>.</li>
</ul>
<p><br/></p>
<p>How are the blackboard operations using tuples?</p>
<ul>
<li>The <strong>write</strong> operation writes a tuple (specified as a parameter).
<pre lang="ruby">
ts.write [:message, 'Hi there!']
</pre>
</li>
<li>Reading operations <strong>read</strong> and <strong>take</strong> use tuples in a slightly different way. It is possible to use the <strong>nil</strong> value as a wild card for the position, where it is used.
<ul>
<li>To read any single:
<pre lang="ruby">
ts.take [nil], 0
</pre>
</li>
<li>To read any pair:
<pre lang="ruby">
ts.take [nil, nil], 0
</pre>
</li>
<li>To read any <em>:message</em> type:
<pre lang="ruby">
ts.take [:message, nil], 0
</pre>
</li>
<li>To read any pair, where the second element has value <em>4</em> (not very practical example :):
<pre lang="ruby">
ts.take [nil, 4], 0
</pre>
</li>
<li>To read exactly the tuple <code>[:result, 4]</code>:
<pre lang="ruby">
ts.take [:result, 4], 0
</pre>
</li>
</ul>
<p>The second parameter says, how long (in seconds) should a read operation wait until a tuple appears on the blackboard. Zero means to not to wait at all.
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/04/message-and-tuple/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Take Message From Blackboard</title>
		<link>http://www.rubyagent.com/2007/03/take-message-from-blackboard/</link>
		<comments>http://www.rubyagent.com/2007/03/take-message-from-blackboard/#comments</comments>
		<pubDate>Sat, 31 Mar 2007 21:33:09 +0000</pubDate>
		<dc:creator>ondrej</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<category><![CDATA[Howto]]></category>

		<category><![CDATA[Rinda]]></category>

		<category><![CDATA[blackboard]]></category>

		<category><![CDATA[take]]></category>

		<guid isPermaLink="false">http://www.rubyagent.com/?p=12</guid>
		<description><![CDATA[The Rinda multi-agent system environment is already running, on the blackboard is written a message, so the last step is to read it :)
The following functionalities will be shown:

Creation of an agent.
Locating the blackboard.
Taking a message.


Although a logical opposite operation to the write operation should be the read operation, it is not so in the [...]]]></description>
			<content:encoded><![CDATA[<p>The Rinda multi-agent system environment is already running, on the blackboard is written a message, so the last step is to read it :)</p>
<p>The following functionalities will be shown:</p>
<ul>
<li>Creation of an agent.</li>
<li>Locating the blackboard.</li>
<li>Taking a message.</li>
</ul>
<blockquote><p>
Although a logical opposite operation to the <strong>write</strong> operation should be the read operation, it is not so in the blackboard system: the operation <strong>read</strong> only checks if a message is there (this will be shown in a post that will follow); the operation <strong>take</strong> takes a message from the blackboard.
</p></blockquote>
<p><br/></p>
<p>The agent source code is stored in the <code>take.rb</code> file:</p>
<pre lang="Ruby">
require 'rinda/ring'

DRb.start_service

ts = Rinda::RingFinger.primary

result = ts.take [:message, nil], 0

puts &#8220;[0]: #{result[0]}&#8221;
puts &#8220;[1]: #{result[1]}&#8221;
</pre>
<p><br/></p>
<p>Firstly, start the <code>rinda.rb</code> code (for more details <a href="http://www.rubyagent.com/?p=8">see the post about starting multi-agent system environment</a>), then, in a separate console, start the <code>write.rb</code> (for more details <a href="http://www.rubyagent.com/?p=10">see the post about writing a message to the blackboard</a>) and finally, in a separate console or in the same console where you started the write.rb file, type:</p>
<pre lang="bash">
ruby take.rb
</pre>
<p>The agent connects to the blackboard, takes a message and shows two lines:</p>
<pre lang="text">
[0]: message
[1]: Hi there!
</pre>
<p><br/></p>
<p>Files to download: <a href="/files/starting_mase/rinda.rb"><code>rinda.rb</code></a>, <a href="/files/write_msg_bb/write.rb"><code>write.rb</code></a> and <a href="/files/take_msg_bb/take.rb"><code>take.rb</code></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.rubyagent.com/2007/03/take-message-from-blackboard/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
