summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordelano <delano@solutious.com>2011-04-03 16:39:47 -0400
committerdelano <delano@solutious.com>2011-04-03 16:39:47 -0400
commit73d75b2c3a5465392fd6210dbb844c49dd043cdc (patch)
tree23d48166dce070d8a517b0d3551a82a6bb1c8efa
parentbfa11f12ba9af1862a0deaf6681de7739f108141 (diff)
downloadnet-ssh-multi-73d75b2c3a5465392fd6210dbb844c49dd043cdc.tar.gz
Updated docs
-rw-r--r--classes/Net.html87
-rw-r--r--classes/Net/SSH.html87
-rw-r--r--classes/Net/SSH/Multi.html154
-rw-r--r--classes/Net/SSH/Multi/Channel.html537
-rw-r--r--classes/Net/SSH/Multi/ChannelProxy.html166
-rw-r--r--classes/Net/SSH/Multi/DynamicServer.html241
-rw-r--r--classes/Net/SSH/Multi/PendingConnection.html306
-rw-r--r--classes/Net/SSH/Multi/Server.html438
-rw-r--r--classes/Net/SSH/Multi/ServerList.html224
-rw-r--r--classes/Net/SSH/Multi/Session.html560
-rw-r--r--classes/Net/SSH/Multi/SessionActions.html272
-rw-r--r--classes/Net/SSH/Multi/Subsession.html169
-rw-r--r--classes/Net/SSH/Multi/Version.html117
-rw-r--r--created.rid1
-rw-r--r--files/CHANGELOG_rdoc.html86
-rw-r--r--files/README_rdoc.html156
-rw-r--r--files/lib/net/ssh/multi/channel_proxy_rb.html49
-rw-r--r--files/lib/net/ssh/multi/channel_rb.html49
-rw-r--r--files/lib/net/ssh/multi/dynamic_server_rb.html57
-rw-r--r--files/lib/net/ssh/multi/pending_connection_rb.html57
-rw-r--r--files/lib/net/ssh/multi/server_list_rb.html58
-rw-r--r--files/lib/net/ssh/multi/server_rb.html57
-rw-r--r--files/lib/net/ssh/multi/session_actions_rb.html49
-rw-r--r--files/lib/net/ssh/multi/session_rb.html65
-rw-r--r--files/lib/net/ssh/multi/subsession_rb.html57
-rw-r--r--files/lib/net/ssh/multi/version_rb.html57
-rw-r--r--files/lib/net/ssh/multi_rb.html57
-rw-r--r--fr_class_index.html23
-rw-r--r--fr_file_index.html32
-rw-r--r--fr_method_index.html4567
-rw-r--r--index.html16
-rw-r--r--rdoc-style.css328
32 files changed, 9178 insertions, 1 deletions
diff --git a/classes/Net.html b/classes/Net.html
new file mode 100644
index 0000000..a4b4cc9
--- /dev/null
+++ b/classes/Net.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Module</span>
+ Net
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../files/lib/net/ssh/multi/channel_rb.html">lib/net/ssh/multi/channel.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/channel_proxy_rb.html">lib/net/ssh/multi/channel_proxy.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/dynamic_server_rb.html">lib/net/ssh/multi/dynamic_server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/pending_connection_rb.html">lib/net/ssh/multi/pending_connection.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/server_rb.html">lib/net/ssh/multi/server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/server_list_rb.html">lib/net/ssh/multi/server_list.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/session_actions_rb.html">lib/net/ssh/multi/session_actions.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/subsession_rb.html">lib/net/ssh/multi/subsession.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi/version_rb.html">lib/net/ssh/multi/version.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../files/lib/net/ssh/multi_rb.html">lib/net/ssh/multi.rb</a>
+ </li>
+ <li>
+ <a class='show' href='#' onclick='this.parentNode.parentNode.className += " expanded"; this.parentNode.removeChild(this); return false'>show all</a>
+ </li>
+ </ol>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='section'>
+ <div id='class-list'>
+ <h2>Classes and Modules</h2>
+ Module <a href="Net/SSH.html" class="link">Net::SSH</a><br />
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH.html b/classes/Net/SSH.html
new file mode 100644
index 0000000..241010c
--- /dev/null
+++ b/classes/Net/SSH.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Module</span>
+ Net::SSH
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../files/lib/net/ssh/multi/channel_rb.html">lib/net/ssh/multi/channel.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/channel_proxy_rb.html">lib/net/ssh/multi/channel_proxy.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/dynamic_server_rb.html">lib/net/ssh/multi/dynamic_server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/pending_connection_rb.html">lib/net/ssh/multi/pending_connection.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/server_rb.html">lib/net/ssh/multi/server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/server_list_rb.html">lib/net/ssh/multi/server_list.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/session_actions_rb.html">lib/net/ssh/multi/session_actions.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/subsession_rb.html">lib/net/ssh/multi/subsession.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi/version_rb.html">lib/net/ssh/multi/version.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../files/lib/net/ssh/multi_rb.html">lib/net/ssh/multi.rb</a>
+ </li>
+ <li>
+ <a class='show' href='#' onclick='this.parentNode.parentNode.className += " expanded"; this.parentNode.removeChild(this); return false'>show all</a>
+ </li>
+ </ol>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='section'>
+ <div id='class-list'>
+ <h2>Classes and Modules</h2>
+ Module <a href="SSH/Multi.html" class="link">Net::SSH::Multi</a><br />
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi.html b/classes/Net/SSH/Multi.html
new file mode 100644
index 0000000..2fd28f8
--- /dev/null
+++ b/classes/Net/SSH/Multi.html
@@ -0,0 +1,154 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Module</span>
+ Net::SSH::Multi
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../files/lib/net/ssh/multi/channel_rb.html">lib/net/ssh/multi/channel.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/channel_proxy_rb.html">lib/net/ssh/multi/channel_proxy.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/dynamic_server_rb.html">lib/net/ssh/multi/dynamic_server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/pending_connection_rb.html">lib/net/ssh/multi/pending_connection.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/server_rb.html">lib/net/ssh/multi/server.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/server_list_rb.html">lib/net/ssh/multi/server_list.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/session_actions_rb.html">lib/net/ssh/multi/session_actions.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/subsession_rb.html">lib/net/ssh/multi/subsession.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi/version_rb.html">lib/net/ssh/multi/version.rb</a>
+ </li>
+ <li class='other'>
+ <a href="../../../files/lib/net/ssh/multi_rb.html">lib/net/ssh/multi.rb</a>
+ </li>
+ <li>
+ <a class='show' href='#' onclick='this.parentNode.parentNode.className += " expanded"; this.parentNode.removeChild(this); return false'>show all</a>
+ </li>
+ </ol>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ <a href="Multi.html">Net::SSH::Multi</a> is a library for controlling
+ multiple <a href="../SSH.html">Net::SSH</a> connections via a single
+ interface. It exposes an API similar to that of
+ Net::SSH::Connection::Session and Net::SSH::Connection::Channel, making it
+ simpler to adapt programs designed for single connections to be used with
+ multiple connections.
+ </p>
+ <p>
+ This library is particularly useful for automating repetitive tasks that
+ must be performed on multiple machines. It executes the commands in
+ parallel, and allows commands to be executed on subsets of servers (defined
+ by groups).
+ </p>
+ <pre>require 'net/ssh/multi'&#x000A;&#x000A;Net::SSH::Multi.start do |session|&#x000A; # access servers via a gateway&#x000A; session.via 'gateway', 'gateway-user'&#x000A;&#x000A; # define the servers we want to use&#x000A; session.use 'user1@host1'&#x000A; session.use 'user2@host2'&#x000A;&#x000A; # define servers in groups for more granular access&#x000A; session.group :app do&#x000A; session.use 'user@app1'&#x000A; session.use 'user@app2'&#x000A; end&#x000A;&#x000A; # execute commands on all servers&#x000A; session.exec &quot;uptime&quot;&#x000A;&#x000A; # execute commands on a subset of servers&#x000A; session.with(:app).exec &quot;hostname&quot;&#x000A;&#x000A; # run the aggregated event loop&#x000A; session.loop&#x000A;end</pre>
+ <p>
+ See <a href="Multi/Session.html">Net::SSH::Multi::Session</a> for more
+ documentation.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000001">start</a></li>
+ </ol>
+ </div>
+ <div id='section'>
+ <div id='class-list'>
+ <h2>Classes and Modules</h2>
+ Module <a href="Multi/SessionActions.html" class="link">Net::SSH::Multi::SessionActions</a><br />
+ Class <a href="Multi/Channel.html" class="link">Net::SSH::Multi::Channel</a><br />
+ Class <a href="Multi/ChannelProxy.html" class="link">Net::SSH::Multi::ChannelProxy</a><br />
+ Class <a href="Multi/DynamicServer.html" class="link">Net::SSH::Multi::DynamicServer</a><br />
+ Class <a href="Multi/PendingConnection.html" class="link">Net::SSH::Multi::PendingConnection</a><br />
+ Class <a href="Multi/Server.html" class="link">Net::SSH::Multi::Server</a><br />
+ Class <a href="Multi/ServerList.html" class="link">Net::SSH::Multi::ServerList</a><br />
+ Class <a href="Multi/Session.html" class="link">Net::SSH::Multi::Session</a><br />
+ Class <a href="Multi/Subsession.html" class="link">Net::SSH::Multi::Subsession</a><br />
+ Class <a href="Multi/Version.html" class="link">Net::SSH::Multi::Version</a><br />
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000001'>
+ <a name='M000001'> </a>
+ <div class='synopsis'>
+ <span class='name'>start</span>
+ <span class='arguments'>(options={}) {|session| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ This is a convenience method for instantiating a new <a
+ href="Multi/Session.html">Net::SSH::Multi::Session</a>. If a block is
+ given, the session will be yielded to the block automatically closed (see
+ <a href="Multi/Session.html#M000074">Net::SSH::Multi::Session#close</a>)
+ when the block finishes. Otherwise, the new session will be returned.
+ </p>
+ <pre>Net::SSH::Multi.start do |session|&#x000A; # ...&#x000A;end&#x000A;&#x000A;session = Net::SSH::Multi.start&#x000A;# ...&#x000A;session.close</pre>
+ <p>
+ Any options are passed directly to <a
+ href="Multi/Session.html#M000066">Net::SSH::Multi::Session.new</a> (q.v.).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000001-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000001-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi.rb, line 57</span>&#x000A;57: <span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">start</span>(<span class="ruby-identifier">options</span>={})&#x000A;58: <span class="ruby-identifier">session</span> = <span class="ruby-constant">Session</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">options</span>)&#x000A;59: &#x000A;60: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>&#x000A;61: <span class="ruby-keyword kw">begin</span>&#x000A;62: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">session</span>&#x000A;63: <span class="ruby-identifier">session</span>.<span class="ruby-identifier">loop</span>&#x000A;64: <span class="ruby-identifier">session</span>.<span class="ruby-identifier">close</span>&#x000A;65: <span class="ruby-keyword kw">end</span>&#x000A;66: <span class="ruby-keyword kw">else</span>&#x000A;67: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">session</span>&#x000A;68: <span class="ruby-keyword kw">end</span>&#x000A;69: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/Channel.html b/classes/Net/SSH/Multi/Channel.html
new file mode 100644
index 0000000..779b48c
--- /dev/null
+++ b/classes/Net/SSH/Multi/Channel.html
@@ -0,0 +1,537 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::Channel [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::Channel
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/channel_rb.html">lib/net/ssh/multi/channel.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ <a href="Channel.html">Net::SSH::Multi::Channel</a> encapsulates a
+ collection of Net::SSH::Connection::Channel instances from multiple
+ different connections. It allows for operations to be performed on all
+ contained channels, simultaneously, using an interface mostly identical to
+ Net::SSH::Connection::Channel itself.
+ </p>
+ <p>
+ You typically obtain a <a href="Channel.html">Net::SSH::Multi::Channel</a>
+ instance via Net::SSH::Multi::Session#open_channel or
+ Net::SSH::Multi::Session#exec, though there is nothing stopping you from
+ instantiating one yourself with a handful of Net::SSH::Connection::Channel
+ objects (though they should be associated with connections managed by a <a
+ href="Session.html">Net::SSH::Multi::Session</a> object for consistent
+ behavior).
+ </p>
+ <pre>channel = session.open_channel do |ch|&#x000A; # ...&#x000A;end&#x000A;&#x000A;channel.wait</pre>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000009">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000011">[]</a></li>
+ <li><a href="#M000012">[]=</a></li>
+ <li><a href="#M000016">active?</a></li>
+ <li><a href="#M000018">close</a></li>
+ <li><a href="#M000010">each</a></li>
+ <li><a href="#M000019">eof!</a></li>
+ <li><a href="#M000013">exec</a></li>
+ <li><a href="#M000023">on_close</a></li>
+ <li><a href="#M000020">on_data</a></li>
+ <li><a href="#M000024">on_eof</a></li>
+ <li><a href="#M000021">on_extended_data</a></li>
+ <li><a href="#M000025">on_open_failed</a></li>
+ <li><a href="#M000022">on_process</a></li>
+ <li><a href="#M000026">on_request</a></li>
+ <li><a href="#M000014">request_pty</a></li>
+ <li><a href="#M000015">send_data</a></li>
+ <li><a href="#M000017">wait</a></li>
+ </ol>
+ </div>
+ <div id='context'>
+ <div id='includes'>
+ <h2>Included modules</h2>
+ <ol>
+ <li>Enumerable</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>channels</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The collection of Net::SSH::Connection::Channel instances that this
+ multi-channel aggregates.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>connection</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The <a href="Session.html">Net::SSH::Multi::Session</a> instance that
+ controls this channel collection.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>properties</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ A Hash of custom properties that may be set and queried on this object.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000009'>
+ <a name='M000009'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(connection, channels)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Instantiate a new <a href="Channel.html">Net::SSH::Multi::Channel</a>
+ instance, controlled by the given <tt>connection</tt> (a <a
+ href="Session.html">Net::SSH::Multi::Session</a> object) and wrapping the
+ given <tt>channels</tt> (Net::SSH::Connection::Channel instances).
+ </p>
+ <p>
+ You will typically never call this directly; rather, you&#8217;ll get your
+ multi-channel references via Net::SSH::Multi::Session#open_channel and
+ friends.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000009-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000009-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 38</span>&#x000A;38: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">connection</span>, <span class="ruby-identifier">channels</span>)&#x000A;39: <span class="ruby-ivar">@connection</span> = <span class="ruby-identifier">connection</span>&#x000A;40: <span class="ruby-ivar">@channels</span> = <span class="ruby-identifier">channels</span>&#x000A;41: <span class="ruby-ivar">@properties</span> = {}&#x000A;42: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000011'>
+ <a name='M000011'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]</span>
+ <span class='arguments'>(key)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Retrieve the property (see properties) with the given <tt>key</tt>.
+ </p>
+ <pre>host = channel[:host]</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000011-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000011-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 53</span>&#x000A;53: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]</span>(<span class="ruby-identifier">key</span>)&#x000A;54: <span class="ruby-ivar">@properties</span>[<span class="ruby-identifier">key</span>]&#x000A;55: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000012'>
+ <a name='M000012'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]=</span>
+ <span class='arguments'>(key, value)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Set the property (see properties) with the given <tt>key</tt> to the given
+ <tt>value</tt>.
+ </p>
+ <pre>channel[:visited] = true</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000012-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000012-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 61</span>&#x000A;61: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]=</span>(<span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span>)&#x000A;62: <span class="ruby-ivar">@properties</span>[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>&#x000A;63: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000016'>
+ <a name='M000016'> </a>
+ <div class='synopsis'>
+ <span class='name'>active?</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns true as long as any of the component channels are active.
+ </p>
+ <pre>connection.loop { channel.active? }</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000016-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000016-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 112</span>&#x000A;112: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">active?</span>&#x000A;113: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">any?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">active?</span> }&#x000A;114: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000018'>
+ <a name='M000018'> </a>
+ <div class='synopsis'>
+ <span class='name'>close</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Closes all component channels.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000018-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000018-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 127</span>&#x000A;127: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">close</span>&#x000A;128: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">close</span> }&#x000A;129: <span class="ruby-keyword kw">self</span>&#x000A;130: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000010'>
+ <a name='M000010'> </a>
+ <div class='synopsis'>
+ <span class='name'>each</span>
+ <span class='arguments'>() {|channel| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Iterate over each component channel object, yielding each in order to the
+ associated block.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000010-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000010-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 46</span>&#x000A;46: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">each</span>&#x000A;47: <span class="ruby-ivar">@channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">channel</span> }&#x000A;48: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000019'>
+ <a name='M000019'> </a>
+ <div class='synopsis'>
+ <span class='name'>eof!</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Tells the remote process for each component channel not to expect any
+ further data from this end of the channel.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000019-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000019-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 134</span>&#x000A;134: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">eof!</span>&#x000A;135: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">eof!</span> }&#x000A;136: <span class="ruby-keyword kw">self</span>&#x000A;137: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000013'>
+ <a name='M000013'> </a>
+ <div class='synopsis'>
+ <span class='name'>exec</span>
+ <span class='arguments'>(command, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Perform an <tt>exec</tt> command on all component channels. The block, if
+ given, is passed to each component channel, so it will (potentially) be
+ invoked once for every channel in the collection. The block will receive
+ two parameters: the specific channel object being operated on, and a
+ boolean indicating whether the exec succeeded or not.
+ </p>
+ <pre>channel.exec &quot;ls -l&quot; do |ch, success|&#x000A; # ...&#x000A;end</pre>
+ <p>
+ See the documentation in <a href="../../SSH.html">Net::SSH</a> for
+ Net::SSH::Connection::Channel#exec for more information on how to work with
+ the callback.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000013-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000013-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 77</span>&#x000A;77: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">exec</span>(<span class="ruby-identifier">command</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;78: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">exec</span>(<span class="ruby-identifier">command</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;79: <span class="ruby-keyword kw">self</span>&#x000A;80: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000023'>
+ <a name='M000023'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_close</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote server terminates the channel. The callback will be invoked with one
+ argument: the specific channel object being closed.
+ </p>
+ <pre>channel.on_close do |ch|&#x000A; # ...&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000023-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000023-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 185</span>&#x000A;185: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_close</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;186: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_close</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;187: <span class="ruby-keyword kw">self</span>&#x000A;188: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000020'>
+ <a name='M000020'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_data</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote process emits data (usually on its <tt>stdout</tt> stream). The
+ block will be invoked with two arguments: the specific channel object, and
+ the data that was received.
+ </p>
+ <pre>channel.on_data do |ch, data|&#x000A; puts &quot;got data: #{data}&quot;&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000020-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000020-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 147</span>&#x000A;147: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_data</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;148: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_data</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;149: <span class="ruby-keyword kw">self</span>&#x000A;150: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000024'>
+ <a name='M000024'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_eof</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote server has no further data to send. The callback will be invoked
+ with one argument: the specific channel object being marked EOF.
+ </p>
+ <pre>channel.on_eof do |ch|&#x000A; # ...&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000024-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000024-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 197</span>&#x000A;197: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_eof</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;198: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_eof</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;199: <span class="ruby-keyword kw">self</span>&#x000A;200: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000021'>
+ <a name='M000021'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_extended_data</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote process emits &#8220;extended&#8221; data (typically on its
+ <tt>stderr</tt> stream). The block will be invoked with three arguments:
+ the specific channel object, an integer describing the data type (usually a
+ 1 for <tt>stderr</tt>) and the data that was received.
+ </p>
+ <pre>channel.on_extended_data do |ch, type, data|&#x000A; puts &quot;got extended data: #{data}&quot;&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000021-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000021-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 161</span>&#x000A;161: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_extended_data</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;162: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_extended_data</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;163: <span class="ruby-keyword kw">self</span>&#x000A;164: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000025'>
+ <a name='M000025'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_open_failed</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote server is unable to open the channel. The callback will be invoked
+ with three arguments: the channel object that couldn&#8217;t be opened, a
+ description of the error (as a string), and an integer code representing
+ the error.
+ </p>
+ <pre>channel.on_open_failed do |ch, description, code|&#x000A; # ...&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000025-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000025-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 211</span>&#x000A;211: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_open_failed</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;212: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_open_failed</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;213: <span class="ruby-keyword kw">self</span>&#x000A;214: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000022'>
+ <a name='M000022'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_process</span>
+ <span class='arguments'>(&amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked during the
+ idle portion of the connection event loop. The callback will be invoked
+ with one argument: the specific channel object being processed.
+ </p>
+ <pre>channel.on_process do |ch|&#x000A; # ...&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000022-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000022-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 173</span>&#x000A;173: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_process</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;174: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_process</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;175: <span class="ruby-keyword kw">self</span>&#x000A;176: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000026'>
+ <a name='M000026'> </a>
+ <div class='synopsis'>
+ <span class='name'>on_request</span>
+ <span class='arguments'>(type, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Registers a callback on all component channels, to be invoked when the
+ remote server sends a channel request of the given <tt>type</tt>. The
+ callback will be invoked with two arguments: the specific channel object
+ receiving the request, and a Net::SSH::Buffer instance containing the
+ request-specific data.
+ </p>
+ <pre>channel.on_request(&quot;exit-status&quot;) do |ch, data|&#x000A; puts &quot;exited with #{data.read_long}&quot;&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000026-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000026-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 225</span>&#x000A;225: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on_request</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;226: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_request</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;227: <span class="ruby-keyword kw">self</span>&#x000A;228: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000014'>
+ <a name='M000014'> </a>
+ <div class='synopsis'>
+ <span class='name'>request_pty</span>
+ <span class='arguments'>(opts={}, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Perform a <tt><a href="Channel.html#M000014">request_pty</a></tt> command
+ on all component channels. The block, if given, is passed to each component
+ channel, so it will (potentially) be invoked once for every channel in the
+ collection. The block will receive two parameters: the specific channel
+ object being operated on, and a boolean indicating whether the pty request
+ succeeded or not.
+ </p>
+ <pre>channel.request_pty do |ch, success|&#x000A; # ...&#x000A;end</pre>
+ <p>
+ See the documentation in <a href="../../SSH.html">Net::SSH</a> for
+ Net::SSH::Connection::Channel#request_pty for more information on how to
+ work with the callback.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000014-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000014-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 95</span>&#x000A;95: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">request_pty</span>(<span class="ruby-identifier">opts</span>={}, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;96: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">request_pty</span>(<span class="ruby-identifier">opts</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>) }&#x000A;97: <span class="ruby-keyword kw">self</span>&#x000A;98: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000015'>
+ <a name='M000015'> </a>
+ <div class='synopsis'>
+ <span class='name'>send_data</span>
+ <span class='arguments'>(data)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Send the given <tt>data</tt> to each component channel. It will be sent to
+ the remote process, typically being received on the process&#8217;
+ <tt>stdin</tt> stream.
+ </p>
+ <pre>channel.send_data &quot;password\n&quot;</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000015-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000015-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 104</span>&#x000A;104: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">send_data</span>(<span class="ruby-identifier">data</span>)&#x000A;105: <span class="ruby-identifier">channels</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span> <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">send_data</span>(<span class="ruby-identifier">data</span>) }&#x000A;106: <span class="ruby-keyword kw">self</span>&#x000A;107: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000017'>
+ <a name='M000017'> </a>
+ <div class='synopsis'>
+ <span class='name'>wait</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Runs the connection&#8217;s event loop until the channel is no longer
+ active (see <a href="Channel.html#M000016">active?</a>).
+ </p>
+ <pre>channel.exec &quot;something&quot;&#x000A;channel.wait</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000017-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000017-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel.rb, line 121</span>&#x000A;121: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">wait</span>&#x000A;122: <span class="ruby-identifier">connection</span>.<span class="ruby-identifier">loop</span> { <span class="ruby-identifier">active?</span> }&#x000A;123: <span class="ruby-keyword kw">self</span>&#x000A;124: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/ChannelProxy.html b/classes/Net/SSH/Multi/ChannelProxy.html
new file mode 100644
index 0000000..7a529c3
--- /dev/null
+++ b/classes/Net/SSH/Multi/ChannelProxy.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::ChannelProxy [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::ChannelProxy
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/channel_proxy_rb.html">lib/net/ssh/multi/channel_proxy.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ The <a href="ChannelProxy.html">ChannelProxy</a> is a delegate class that
+ represents a channel that has not yet been opened. It is only used when <a
+ href="../Multi.html">Net::SSH::Multi</a> is running with with a concurrent
+ connections limit (see Net::SSH::Multi::Session#concurrent_connections).
+ </p>
+ <p>
+ You&#8217;ll never need to instantiate one of these directly, and will
+ probably (if all goes well!) never even notice when one of these is in use.
+ Essentially, it is spawned by a <a
+ href="PendingConnection.html">Net::SSH::Multi::PendingConnection</a> when
+ the pending connection is asked to open a channel. Any actions performed on
+ the channel proxy will then be recorded, until a real channel is set as the
+ delegate (see <a href="ChannelProxy.html#M000028">delegate_to</a>). At that
+ point, all recorded actions will be replayed on the channel, and any
+ subsequent actions will be immediately delegated to the channel.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000027">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000028">delegate_to</a></li>
+ <li><a href="#M000029">method_missing</a></li>
+ </ol>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>on_confirm</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ This is the &#8220;on confirm&#8221; callback that gets called when the
+ real channel is opened.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000027'>
+ <a name='M000027'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(&amp;on_confirm)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Instantiates a new channel proxy with the given <tt>on_confirm</tt>
+ callback.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000027-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000027-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel_proxy.rb, line 21</span>&#x000A;21: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">on_confirm</span>)&#x000A;22: <span class="ruby-ivar">@on_confirm</span> = <span class="ruby-identifier">on_confirm</span>&#x000A;23: <span class="ruby-ivar">@recordings</span> = []&#x000A;24: <span class="ruby-ivar">@channel</span> = <span class="ruby-keyword kw">nil</span>&#x000A;25: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000028'>
+ <a name='M000028'> </a>
+ <div class='synopsis'>
+ <span class='name'>delegate_to</span>
+ <span class='arguments'>(channel)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Instructs the proxy to delegate all further actions to the given
+ <tt>channel</tt> (which must be an instance of
+ Net::SSH::Connection::Channel). All recorded actions are immediately
+ replayed, in order, against the delegate channel.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000028-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000028-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel_proxy.rb, line 30</span>&#x000A;30: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">delegate_to</span>(<span class="ruby-identifier">channel</span>)&#x000A;31: <span class="ruby-ivar">@channel</span> = <span class="ruby-identifier">channel</span>&#x000A;32: <span class="ruby-ivar">@recordings</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">sym</span>, <span class="ruby-identifier">args</span>, <span class="ruby-identifier">block</span><span class="ruby-operator">|</span>&#x000A;33: <span class="ruby-ivar">@channel</span>.<span class="ruby-identifier">__send__</span>(<span class="ruby-identifier">sym</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;34: <span class="ruby-keyword kw">end</span>&#x000A;35: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000029'>
+ <a name='M000029'> </a>
+ <div class='synopsis'>
+ <span class='name'>method_missing</span>
+ <span class='arguments'>(sym, *args, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ If a channel delegate has been specified (see <a
+ href="ChannelProxy.html#M000028">delegate_to</a>), the method will be
+ immediately sent to the delegate. Otherwise, the call is added to the list
+ of recorded method calls, to be played back when a delegate is specified.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000029-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000029-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/channel_proxy.rb, line 41</span>&#x000A;41: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">method_missing</span>(<span class="ruby-identifier">sym</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;42: <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@channel</span>&#x000A;43: <span class="ruby-ivar">@channel</span>.<span class="ruby-identifier">__send__</span>(<span class="ruby-identifier">sym</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;44: <span class="ruby-keyword kw">else</span>&#x000A;45: <span class="ruby-ivar">@recordings</span> <span class="ruby-operator">&lt;&lt;</span> [<span class="ruby-identifier">sym</span>, <span class="ruby-identifier">args</span>, <span class="ruby-identifier">block</span>]&#x000A;46: <span class="ruby-keyword kw">end</span>&#x000A;47: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/DynamicServer.html b/classes/Net/SSH/Multi/DynamicServer.html
new file mode 100644
index 0000000..2829095
--- /dev/null
+++ b/classes/Net/SSH/Multi/DynamicServer.html
@@ -0,0 +1,241 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::DynamicServer [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::DynamicServer
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/dynamic_server_rb.html">lib/net/ssh/multi/dynamic_server.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ Represents a lazily evaluated collection of servers. This will usually be
+ created via <a
+ href="Session.html#M000069">Net::SSH::Multi::Session#use</a>(&amp;block),
+ and is useful for creating server definitions where the name or address of
+ the servers are not known until run-time.
+ </p>
+ <pre>session.use { lookup_ip_address_of_server }</pre>
+ <p>
+ This prevents <tt>lookup_ip_address_of_server</tt> from being invoked
+ unless the server is actually needed, at which point it is invoked and the
+ result cached.
+ </p>
+ <p>
+ The callback should return either <tt>nil</tt> (in which case no new
+ servers are instantiated), a String (representing a connection
+ specification), an array of Strings, or an array of <a
+ href="Server.html">Net::SSH::Multi::Server</a> instances.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000030">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000031">[]</a></li>
+ <li><a href="#M000032">[]=</a></li>
+ <li><a href="#M000033">each</a></li>
+ <li><a href="#M000034">evaluate!</a></li>
+ <li><a href="#M000035">to_ary</a></li>
+ </ol>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>callback</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The Proc object to call to evaluate the server(s)
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>master</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The <a href="Session.html">Net::SSH::Multi::Session</a> instance that owns
+ this dynamic server record.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>options</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The hash of options that will be used to initialize the server records.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000030'>
+ <a name='M000030'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(master, options, callback)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Create a new <a href="DynamicServer.html">DynamicServer</a> record, owned
+ by the given <a href="Session.html">Net::SSH::Multi::Session</a>
+ <tt>master</tt>, with the given hash of <tt>options</tt>, and using the
+ given Proc <tt>callback</tt> to lazily evaluate the actual server
+ instances.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000030-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000030-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/dynamic_server.rb, line 32</span>&#x000A;32: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">master</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">callback</span>)&#x000A;33: <span class="ruby-ivar">@master</span>, <span class="ruby-ivar">@options</span>, <span class="ruby-ivar">@callback</span> = <span class="ruby-identifier">master</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">callback</span>&#x000A;34: <span class="ruby-ivar">@servers</span> = <span class="ruby-keyword kw">nil</span>&#x000A;35: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000031'>
+ <a name='M000031'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]</span>
+ <span class='arguments'>(key)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the value for the given <tt>key</tt> in the :properties hash of the
+ <tt>options</tt>. If no :properties hash exists in <tt>options</tt>, this
+ returns <tt>nil</tt>.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000031-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000031-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/dynamic_server.rb, line 39</span>&#x000A;39: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]</span>(<span class="ruby-identifier">key</span>)&#x000A;40: (<span class="ruby-identifier">options</span>[<span class="ruby-identifier">:properties</span>] <span class="ruby-operator">||=</span> {})[<span class="ruby-identifier">key</span>]&#x000A;41: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000032'>
+ <a name='M000032'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]=</span>
+ <span class='arguments'>(key, value)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Sets the given key/value pair in the <tt>:properties</tt> key in the
+ options hash. If the options hash has no :properties key, it will be
+ created.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000032-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000032-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/dynamic_server.rb, line 45</span>&#x000A;45: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]=</span>(<span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span>)&#x000A;46: (<span class="ruby-identifier">options</span>[<span class="ruby-identifier">:properties</span>] <span class="ruby-operator">||=</span> {})[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>&#x000A;47: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000033'>
+ <a name='M000033'> </a>
+ <div class='synopsis'>
+ <span class='name'>each</span>
+ <span class='arguments'>() {|server| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Iterates over every instantiated server record in this dynamic server. If
+ the servers have not yet been instantiated, this does nothing (e.g., it
+ does <em>not</em> automatically invoke <a
+ href="DynamicServer.html#M000034">evaluate!</a>).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000033-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000033-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/dynamic_server.rb, line 52</span>&#x000A;52: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">each</span>&#x000A;53: (<span class="ruby-ivar">@servers</span> <span class="ruby-operator">||</span> []).<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">server</span> }&#x000A;54: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000034'>
+ <a name='M000034'> </a>
+ <div class='synopsis'>
+ <span class='name'>evaluate!</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Evaluates the callback and instantiates the servers, memoizing the result.
+ Subsequent calls to <a href="DynamicServer.html#M000034">evaluate!</a> will
+ simply return the cached list of servers.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000034-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000034-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/dynamic_server.rb, line 59</span>&#x000A;59: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">evaluate!</span>&#x000A;60: <span class="ruby-ivar">@servers</span> <span class="ruby-operator">||=</span> <span class="ruby-constant">Array</span>(<span class="ruby-identifier">callback</span>[<span class="ruby-identifier">options</span>]).<span class="ruby-identifier">map</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span>&#x000A;61: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">server</span>&#x000A;62: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">String</span> <span class="ruby-keyword kw">then</span> <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">SSH</span><span class="ruby-operator">::</span><span class="ruby-constant">Multi</span><span class="ruby-operator">::</span><span class="ruby-constant">Server</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">master</span>, <span class="ruby-identifier">server</span>, <span class="ruby-identifier">options</span>)&#x000A;63: <span class="ruby-keyword kw">else</span> <span class="ruby-identifier">server</span>&#x000A;64: <span class="ruby-keyword kw">end</span>&#x000A;65: <span class="ruby-keyword kw">end</span>&#x000A;66: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000035'>
+ <a name='M000035'> </a>
+ <div class='synopsis'>
+ <span class='name'>to_ary</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Alias for <a href="DynamicServer.html#M000034">evaluate!</a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/PendingConnection.html b/classes/Net/SSH/Multi/PendingConnection.html
new file mode 100644
index 0000000..9c59193
--- /dev/null
+++ b/classes/Net/SSH/Multi/PendingConnection.html
@@ -0,0 +1,306 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::PendingConnection [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::PendingConnection
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/pending_connection_rb.html">lib/net/ssh/multi/pending_connection.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ A <a href="PendingConnection.html">PendingConnection</a> instance mimics a
+ Net::SSH::Connection::Session instance, without actually being an open
+ connection to a server. It is used by <a
+ href="Session.html">Net::SSH::Multi::Session</a> when a concurrent
+ connection limit is in effect, so that a server can hang on to a
+ &#8220;connection&#8221; that isn&#8217;t really a connection.
+ </p>
+ <p>
+ Any requests against this connection (like <a
+ href="PendingConnection.html#M000038">open_channel</a> or <a
+ href="PendingConnection.html#M000039">send_global_request</a>) are not
+ actually sent, but are added to a list of recordings. When the real session
+ is opened and replaces this pending connection, all recorded actions will
+ be replayed against that session.
+ </p>
+ <p>
+ You&#8217;ll never need to initialize one of these directly, and (if all
+ goes well!) should never even notice that one of these is in use. <a
+ href="Session.html">Net::SSH::Multi::Session</a> will instantiate these as
+ needed, and only when there is a concurrent connection limit.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000036">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000040">busy?</a></li>
+ <li><a href="#M000042">channels</a></li>
+ <li><a href="#M000041">close</a></li>
+ <li><a href="#M000045">listeners</a></li>
+ <li><a href="#M000038">open_channel</a></li>
+ <li><a href="#M000044">postprocess</a></li>
+ <li><a href="#M000043">preprocess</a></li>
+ <li><a href="#M000037">replace_with</a></li>
+ <li><a href="#M000039">send_global_request</a></li>
+ </ol>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>server</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The <a href="Server.html">Net::SSH::Multi::Server</a> object that
+ &#8220;owns&#8221; this pending connection.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000036'>
+ <a name='M000036'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(server)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Instantiates a new pending connection for the given <a
+ href="Server.html">Net::SSH::Multi::Server</a> object.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000036-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000036-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 52</span>&#x000A;52: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">server</span>)&#x000A;53: <span class="ruby-ivar">@server</span> = <span class="ruby-identifier">server</span>&#x000A;54: <span class="ruby-ivar">@recordings</span> = []&#x000A;55: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000040'>
+ <a name='M000040'> </a>
+ <div class='synopsis'>
+ <span class='name'>busy?</span>
+ <span class='arguments'>(include_invisible=false)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Always returns <tt>true</tt>, so that the pending connection looks active
+ until it can be truly opened and replaced with a real connection.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000040-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000040-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 82</span>&#x000A;82: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">busy?</span>(<span class="ruby-identifier">include_invisible</span>=<span class="ruby-keyword kw">false</span>)&#x000A;83: <span class="ruby-keyword kw">true</span>&#x000A;84: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000042'>
+ <a name='M000042'> </a>
+ <div class='synopsis'>
+ <span class='name'>channels</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns an empty array, since a pending connection cannot have any real
+ channels.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000042-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000042-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 92</span>&#x000A;92: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">channels</span>&#x000A;93: []&#x000A;94: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000041'>
+ <a name='M000041'> </a>
+ <div class='synopsis'>
+ <span class='name'>close</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Does nothing, except to make a pending connection quack like a real
+ connection.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000041-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000041-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 87</span>&#x000A;87: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">close</span>&#x000A;88: <span class="ruby-keyword kw">self</span>&#x000A;89: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000045'>
+ <a name='M000045'> </a>
+ <div class='synopsis'>
+ <span class='name'>listeners</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns an empty hash, since a pending connection has no real listeners.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000045-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000045-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 107</span>&#x000A;107: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">listeners</span>&#x000A;108: {}&#x000A;109: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000038'>
+ <a name='M000038'> </a>
+ <div class='synopsis'>
+ <span class='name'>open_channel</span>
+ <span class='arguments'>(type=&quot;session&quot;, *extras, &amp;on_confirm)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Records that a channel open request has been made, and returns a new <a
+ href="ChannelProxy.html">Net::SSH::Multi::ChannelProxy</a> object to
+ represent the (as yet unopened) channel.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000038-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000038-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 67</span>&#x000A;67: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">open_channel</span>(<span class="ruby-identifier">type</span>=<span class="ruby-value str">&quot;session&quot;</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extras</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">on_confirm</span>)&#x000A;68: <span class="ruby-identifier">channel</span> = <span class="ruby-constant">ChannelProxy</span>.<span class="ruby-identifier">new</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">on_confirm</span>)&#x000A;69: <span class="ruby-ivar">@recordings</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-constant">ChannelOpenRecording</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">type</span>, <span class="ruby-identifier">extras</span>, <span class="ruby-identifier">channel</span>)&#x000A;70: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">channel</span>&#x000A;71: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000044'>
+ <a name='M000044'> </a>
+ <div class='synopsis'>
+ <span class='name'>postprocess</span>
+ <span class='arguments'>(readers, writers)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns <tt>true</tt>, and does nothing else.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000044-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000044-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 102</span>&#x000A;102: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">postprocess</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>)&#x000A;103: <span class="ruby-keyword kw">true</span>&#x000A;104: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000043'>
+ <a name='M000043'> </a>
+ <div class='synopsis'>
+ <span class='name'>preprocess</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns <tt>true</tt>, and does nothing else.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000043-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000043-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 97</span>&#x000A;97: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">preprocess</span>&#x000A;98: <span class="ruby-keyword kw">true</span>&#x000A;99: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000037'>
+ <a name='M000037'> </a>
+ <div class='synopsis'>
+ <span class='name'>replace_with</span>
+ <span class='arguments'>(session)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Instructs the pending session to replay all of its recordings against the
+ given <tt>session</tt>, and to then replace itself with the given session.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000037-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000037-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 59</span>&#x000A;59: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">replace_with</span>(<span class="ruby-identifier">session</span>)&#x000A;60: <span class="ruby-ivar">@recordings</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">recording</span><span class="ruby-operator">|</span> <span class="ruby-identifier">recording</span>.<span class="ruby-identifier">replay_on</span>(<span class="ruby-identifier">session</span>) }&#x000A;61: <span class="ruby-ivar">@server</span>.<span class="ruby-identifier">replace_session</span>(<span class="ruby-identifier">session</span>)&#x000A;62: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000039'>
+ <a name='M000039'> </a>
+ <div class='synopsis'>
+ <span class='name'>send_global_request</span>
+ <span class='arguments'>(type, *extra, &amp;callback)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Records that a global request has been made. The request is not actually
+ sent, and won&#8217;t be until <a
+ href="PendingConnection.html#M000037">replace_with</a> is called.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000039-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000039-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/pending_connection.rb, line 75</span>&#x000A;75: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">send_global_request</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extra</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">callback</span>)&#x000A;76: <span class="ruby-ivar">@recordings</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-constant">SendGlobalRequestRecording</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">type</span>, <span class="ruby-identifier">extra</span>, <span class="ruby-identifier">callback</span>)&#x000A;77: <span class="ruby-keyword kw">self</span>&#x000A;78: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/Server.html b/classes/Net/SSH/Multi/Server.html
new file mode 100644
index 0000000..17be26b
--- /dev/null
+++ b/classes/Net/SSH/Multi/Server.html
@@ -0,0 +1,438 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::Server [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::Server
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/server_rb.html">lib/net/ssh/multi/server.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ Encapsulates the connection information for a single remote server, as well
+ as the <a href="../../SSH.html">Net::SSH</a> session corresponding to that
+ information. You&#8217;ll rarely need to instantiate one of these directly:
+ instead, you should use <a
+ href="Session.html#M000069">Net::SSH::Multi::Session#use</a>.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000046">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000050">&lt;=&gt;</a></li>
+ <li><a href="#M000047">[]</a></li>
+ <li><a href="#M000048">[]=</a></li>
+ <li><a href="#M000057">busy?</a></li>
+ <li><a href="#M000058">close</a></li>
+ <li><a href="#M000055">fail!</a></li>
+ <li><a href="#M000054">failed?</a></li>
+ <li><a href="#M000051">hash</a></li>
+ <li><a href="#M000053">inspect</a></li>
+ <li><a href="#M000049">port</a></li>
+ <li><a href="#M000056">session</a></li>
+ <li><a href="#M000052">to_s</a></li>
+ </ol>
+ </div>
+ <div id='context'>
+ <div id='includes'>
+ <h2>Included modules</h2>
+ <ol>
+ <li>Comparable</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ <div id='aliases-list'>
+ <h2>External Aliases</h2>
+ <div class='name-list'>
+ <table summary='External aliases'>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>==</td>
+ <td>-&gt;</td>
+ <td class='context-item-value'>eql?</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>gateway</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The Net::SSH::Gateway instance to use to establish the connection. Will be
+ <tt>nil</tt> if the connection should be established without a gateway.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>host</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The host name (or IP address) of the server to connect to.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>master</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The <a href="Session.html">Net::SSH::Multi::Session</a> instance that
+ manages this server instance.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>options</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The Hash of additional options to pass to <a
+ href="../../SSH.html">Net::SSH</a> when connecting (including things like
+ :password, and so forth).
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>user</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The user name to use when logging into the server.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000046'>
+ <a name='M000046'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(master, host, options={})</span>
+ </div>
+ <div class='description'>
+ <p>
+ Creates a new <a href="Server.html">Server</a> instance with the given
+ connection information. The <tt>master</tt> argument must be a reference to
+ the <a href="Session.html">Net::SSH::Multi::Session</a> instance that will
+ manage this server reference. The <tt>options</tt> hash must conform to the
+ options described for Net::SSH::start, with two additions:
+ </p>
+ <ul>
+ <li>:via => a Net::SSH::Gateway instance to use when establishing a connection
+ to this server.
+
+ </li>
+ <li>:user => the name of the user to use when logging into this server.
+
+ </li>
+ </ul>
+ <p>
+ The <tt>host</tt> argument may include the username and port number, in
+ which case those values take precedence over similar values given in the
+ <tt>options</tt>:
+ </p>
+ <pre>server = Net::SSH::Multi::Server.new(session, 'user@host:1234')&#x000A;puts server.user #-&gt; user&#x000A;puts server.port #-&gt; 1234</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000046-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000046-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 43</span>&#x000A;43: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">master</span>, <span class="ruby-identifier">host</span>, <span class="ruby-identifier">options</span>={})&#x000A;44: <span class="ruby-ivar">@master</span> = <span class="ruby-identifier">master</span>&#x000A;45: <span class="ruby-ivar">@options</span> = <span class="ruby-identifier">options</span>.<span class="ruby-identifier">dup</span>&#x000A;46: &#x000A;47: <span class="ruby-ivar">@user</span>, <span class="ruby-ivar">@host</span>, <span class="ruby-identifier">port</span> = <span class="ruby-identifier">host</span>.<span class="ruby-identifier">match</span>(<span class="ruby-regexp re">/^(?:([^;,:=]+)@|)(.*?)(?::(\d+)|)$/</span>)[<span class="ruby-value">1</span>,<span class="ruby-value">3</span>]&#x000A;48: &#x000A;49: <span class="ruby-identifier">user_opt</span>, <span class="ruby-identifier">port_opt</span> = <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">:user</span>), <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">:port</span>)&#x000A;50: &#x000A;51: <span class="ruby-ivar">@user</span> = <span class="ruby-ivar">@user</span> <span class="ruby-operator">||</span> <span class="ruby-identifier">user_opt</span> <span class="ruby-operator">||</span> <span class="ruby-identifier">master</span>.<span class="ruby-identifier">default_user</span>&#x000A;52: <span class="ruby-identifier">port</span> <span class="ruby-operator">||=</span> <span class="ruby-identifier">port_opt</span>&#x000A;53: &#x000A;54: <span class="ruby-ivar">@options</span>[<span class="ruby-identifier">:port</span>] = <span class="ruby-identifier">port</span>.<span class="ruby-identifier">to_i</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">port</span>&#x000A;55: &#x000A;56: <span class="ruby-ivar">@gateway</span> = <span class="ruby-ivar">@options</span>.<span class="ruby-identifier">delete</span>(<span class="ruby-identifier">:via</span>)&#x000A;57: <span class="ruby-ivar">@failed</span> = <span class="ruby-keyword kw">false</span>&#x000A;58: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000050'>
+ <a name='M000050'> </a>
+ <div class='synopsis'>
+ <span class='name'>&lt;=&gt;</span>
+ <span class='arguments'>(server)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Gives server definitions a sort order, and allows comparison.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000050-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000050-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 79</span>&#x000A;79: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">&lt;=&gt;</span>(<span class="ruby-identifier">server</span>)&#x000A;80: [<span class="ruby-identifier">host</span>, <span class="ruby-identifier">port</span>, <span class="ruby-identifier">user</span>] <span class="ruby-operator">&lt;=&gt;</span> [<span class="ruby-identifier">server</span>.<span class="ruby-identifier">host</span>, <span class="ruby-identifier">server</span>.<span class="ruby-identifier">port</span>, <span class="ruby-identifier">server</span>.<span class="ruby-identifier">user</span>]&#x000A;81: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000047'>
+ <a name='M000047'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]</span>
+ <span class='arguments'>(key)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the value of the server property with the given <tt>key</tt>. <a
+ href="Server.html">Server</a> properties are described via the
+ <tt>:properties</tt> key in the options hash when defining the <a
+ href="Server.html">Server</a>.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000047-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000047-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 63</span>&#x000A;63: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]</span>(<span class="ruby-identifier">key</span>)&#x000A;64: (<span class="ruby-identifier">options</span>[<span class="ruby-identifier">:properties</span>] <span class="ruby-operator">||</span> {})[<span class="ruby-identifier">key</span>]&#x000A;65: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000048'>
+ <a name='M000048'> </a>
+ <div class='synopsis'>
+ <span class='name'>[]=</span>
+ <span class='arguments'>(key, value)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Sets the given key/value pair in the <tt>:properties</tt> key in the
+ options hash. If the options hash has no :properties key, it will be
+ created.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000048-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000048-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 69</span>&#x000A;69: <span class="ruby-keyword kw">def</span> <span class="ruby-operator">[]=</span>(<span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span>)&#x000A;70: (<span class="ruby-identifier">options</span>[<span class="ruby-identifier">:properties</span>] <span class="ruby-operator">||=</span> {})[<span class="ruby-identifier">key</span>] = <span class="ruby-identifier">value</span>&#x000A;71: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000057'>
+ <a name='M000057'> </a>
+ <div class='synopsis'>
+ <span class='name'>busy?</span>
+ <span class='arguments'>(include_invisible=false)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns <tt>true</tt> if the session has been opened, and the session is
+ currently busy (as defined by Net::SSH::Connection::Session#busy?).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000057-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000057-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 143</span>&#x000A;143: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">busy?</span>(<span class="ruby-identifier">include_invisible</span>=<span class="ruby-keyword kw">false</span>)&#x000A;144: <span class="ruby-identifier">session</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">session</span>.<span class="ruby-identifier">busy?</span>(<span class="ruby-identifier">include_invisible</span>)&#x000A;145: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000058'>
+ <a name='M000058'> </a>
+ <div class='synopsis'>
+ <span class='name'>close</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Closes this server&#8217;s session. If the session has not yet been opened,
+ this does nothing.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000058-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000058-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 149</span>&#x000A;149: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">close</span>&#x000A;150: <span class="ruby-identifier">session</span>.<span class="ruby-identifier">close</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">session</span>&#x000A;151: <span class="ruby-keyword kw">ensure</span>&#x000A;152: <span class="ruby-identifier">master</span>.<span class="ruby-identifier">server_closed</span>(<span class="ruby-keyword kw">self</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">session</span>&#x000A;153: <span class="ruby-ivar">@session</span> = <span class="ruby-keyword kw">nil</span>&#x000A;154: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000055'>
+ <a name='M000055'> </a>
+ <div class='synopsis'>
+ <span class='name'>fail!</span>
+ <span class='arguments'>(flag=true)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Indicates (by default) that this server has just failed a connection
+ attempt. If <tt>flag</tt> is false, this can be used to reset the failed
+ flag so that a retry may be attempted.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000055-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000055-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 115</span>&#x000A;115: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">fail!</span>(<span class="ruby-identifier">flag</span>=<span class="ruby-keyword kw">true</span>)&#x000A;116: <span class="ruby-ivar">@failed</span> = <span class="ruby-identifier">flag</span>&#x000A;117: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000054'>
+ <a name='M000054'> </a>
+ <div class='synopsis'>
+ <span class='name'>failed?</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns <tt>true</tt> if this server has ever failed a connection attempt.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000054-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000054-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 108</span>&#x000A;108: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">failed?</span>&#x000A;109: <span class="ruby-ivar">@failed</span>&#x000A;110: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000051'>
+ <a name='M000051'> </a>
+ <div class='synopsis'>
+ <span class='name'>hash</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Generates a <tt>Fixnum</tt> hash value for this object. This function has
+ the property that +a.eql?(b)+ implies +a.hash == b.hash+. The hash value is
+ used by class <tt>Hash</tt>. Any hash value that exceeds the capacity of a
+ <tt>Fixnum</tt> will be truncated before being used.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000051-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000051-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 89</span>&#x000A;89: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">hash</span>&#x000A;90: <span class="ruby-ivar">@hash</span> <span class="ruby-operator">||=</span> [<span class="ruby-identifier">host</span>, <span class="ruby-identifier">user</span>, <span class="ruby-identifier">port</span>].<span class="ruby-identifier">hash</span>&#x000A;91: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000053'>
+ <a name='M000053'> </a>
+ <div class='synopsis'>
+ <span class='name'>inspect</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns a human-readable representation of this server instance.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000053-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000053-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 103</span>&#x000A;103: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">inspect</span>&#x000A;104: <span class="ruby-ivar">@inspect</span> <span class="ruby-operator">||=</span> <span class="ruby-value str">&quot;#&lt;%s:0x%x %s&gt;&quot;</span> <span class="ruby-operator">%</span> [<span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">class</span>.<span class="ruby-identifier">name</span>, <span class="ruby-identifier">object_id</span>, <span class="ruby-identifier">to_s</span>]&#x000A;105: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000049'>
+ <a name='M000049'> </a>
+ <div class='synopsis'>
+ <span class='name'>port</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the port number to use for this connection.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000049-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000049-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 74</span>&#x000A;74: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">port</span>&#x000A;75: <span class="ruby-identifier">options</span>[<span class="ruby-identifier">:port</span>] <span class="ruby-operator">||</span> <span class="ruby-value">22</span>&#x000A;76: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000056'>
+ <a name='M000056'> </a>
+ <div class='synopsis'>
+ <span class='name'>session</span>
+ <span class='arguments'>(require_session=false)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the <a href="../../SSH.html">Net::SSH</a> session object for this
+ server. If <tt>require_session</tt> is false and the session has not
+ previously been created, this will return <tt>nil</tt>. If
+ <tt>require_session</tt> is true, the session will be instantiated if it
+ has not already been instantiated, via the <tt>gateway</tt> if one is
+ given, or directly (via Net::SSH::start) otherwise.
+ </p>
+ <pre>if server.session.nil?&#x000A; puts &quot;connecting...&quot;&#x000A; server.session(true)&#x000A;end</pre>
+ <p>
+ Note that the sessions returned by this are &#8220;enhanced&#8221;
+ slightly, to make them easier to deal with in a multi-session environment:
+ they have a :server property automatically set on them, that refers to this
+ object (the <a href="Server.html">Server</a> instance that spawned them).
+ </p>
+ <pre>assert_equal server, server.session[:server]</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000056-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000056-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 136</span>&#x000A;136: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">session</span>(<span class="ruby-identifier">require_session</span>=<span class="ruby-keyword kw">false</span>)&#x000A;137: <span class="ruby-keyword kw">return</span> <span class="ruby-ivar">@session</span> <span class="ruby-keyword kw">if</span> <span class="ruby-ivar">@session</span> <span class="ruby-operator">||</span> <span class="ruby-operator">!</span><span class="ruby-identifier">require_session</span>&#x000A;138: <span class="ruby-ivar">@session</span> <span class="ruby-operator">||=</span> <span class="ruby-identifier">master</span>.<span class="ruby-identifier">next_session</span>(<span class="ruby-keyword kw">self</span>)&#x000A;139: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000052'>
+ <a name='M000052'> </a>
+ <div class='synopsis'>
+ <span class='name'>to_s</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns a human-readable representation of this server instance.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000052-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000052-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server.rb, line 94</span>&#x000A; 94: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">to_s</span>&#x000A; 95: <span class="ruby-ivar">@to_s</span> <span class="ruby-operator">||=</span> <span class="ruby-keyword kw">begin</span>&#x000A; 96: <span class="ruby-identifier">s</span> = <span class="ruby-node">&quot;#{user}@#{host}&quot;</span>&#x000A; 97: <span class="ruby-identifier">s</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-node">&quot;:#{options[:port]}&quot;</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">options</span>[<span class="ruby-identifier">:port</span>]&#x000A; 98: <span class="ruby-identifier">s</span>&#x000A; 99: <span class="ruby-keyword kw">end</span>&#x000A;100: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/ServerList.html b/classes/Net/SSH/Multi/ServerList.html
new file mode 100644
index 0000000..5c29cac
--- /dev/null
+++ b/classes/Net/SSH/Multi/ServerList.html
@@ -0,0 +1,224 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::ServerList [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::ServerList
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/server_list_rb.html">lib/net/ssh/multi/server_list.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ Encapsulates a list of server objects, both dynamic (<a
+ href="DynamicServer.html">Net::SSH::Multi::DynamicServer</a>) and static
+ (<a href="Server.html">Net::SSH::Multi::Server</a>). It attempts to make it
+ transparent whether a dynamic server set has been evaluated or not. Note
+ that a <a href="ServerList.html">ServerList</a> is NOT an Array, though it
+ is Enumerable.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000059">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000060">add</a></li>
+ <li><a href="#M000061">concat</a></li>
+ <li><a href="#M000062">each</a></li>
+ <li><a href="#M000064">flatten</a></li>
+ <li><a href="#M000063">select</a></li>
+ <li><a href="#M000065">to_ary</a></li>
+ </ol>
+ </div>
+ <div id='context'>
+ <div id='includes'>
+ <h2>Included modules</h2>
+ <ol>
+ <li>Enumerable</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000059'>
+ <a name='M000059'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(list=[])</span>
+ </div>
+ <div class='description'>
+ <p>
+ Create a new <a href="ServerList.html">ServerList</a> that wraps the given
+ server list. Duplicate entries will be discarded.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000059-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000059-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 15</span>&#x000A;15: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">list</span>=[])&#x000A;16: <span class="ruby-ivar">@list</span> = <span class="ruby-identifier">list</span>.<span class="ruby-identifier">uniq</span>&#x000A;17: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000060'>
+ <a name='M000060'> </a>
+ <div class='synopsis'>
+ <span class='name'>add</span>
+ <span class='arguments'>(server)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Adds the given server to the list, and returns the argument. If an
+ identical server definition already exists in the collection, the argument
+ is <em>not</em> added, and the existing server record is returned instead.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000060-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000060-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 23</span>&#x000A;23: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">add</span>(<span class="ruby-identifier">server</span>)&#x000A;24: <span class="ruby-identifier">index</span> = <span class="ruby-ivar">@list</span>.<span class="ruby-identifier">index</span>(<span class="ruby-identifier">server</span>)&#x000A;25: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">index</span>&#x000A;26: <span class="ruby-identifier">server</span> = <span class="ruby-ivar">@list</span>[<span class="ruby-identifier">index</span>]&#x000A;27: <span class="ruby-keyword kw">else</span>&#x000A;28: <span class="ruby-ivar">@list</span>.<span class="ruby-identifier">push</span>(<span class="ruby-identifier">server</span>)&#x000A;29: <span class="ruby-keyword kw">end</span>&#x000A;30: <span class="ruby-identifier">server</span>&#x000A;31: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000061'>
+ <a name='M000061'> </a>
+ <div class='synopsis'>
+ <span class='name'>concat</span>
+ <span class='arguments'>(servers)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Adds an array (or otherwise Enumerable list) of servers to this list, by
+ calling <a href="ServerList.html#M000060">add</a> for each argument.
+ Returns <tt>self</tt>.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000061-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000061-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 35</span>&#x000A;35: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">concat</span>(<span class="ruby-identifier">servers</span>)&#x000A;36: <span class="ruby-identifier">servers</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">add</span>(<span class="ruby-identifier">server</span>) }&#x000A;37: <span class="ruby-keyword kw">self</span>&#x000A;38: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000062'>
+ <a name='M000062'> </a>
+ <div class='synopsis'>
+ <span class='name'>each</span>
+ <span class='arguments'>() {|server| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Iterates over each distinct server record in the collection. This will
+ correctly iterate over server records instantiated by a <a
+ href="DynamicServer.html">DynamicServer</a> as well, but only if the
+ dynamic server has been &#8220;evaluated&#8221; (see <a
+ href="DynamicServer.html#M000034">Net::SSH::Multi::DynamicServer#evaluate!</a>).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000062-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000062-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 44</span>&#x000A;44: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">each</span>&#x000A;45: <span class="ruby-ivar">@list</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span>&#x000A;46: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">server</span>&#x000A;47: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">Server</span> <span class="ruby-keyword kw">then</span> <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">server</span>&#x000A;48: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">DynamicServer</span> <span class="ruby-keyword kw">then</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">item</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">item</span> }&#x000A;49: <span class="ruby-keyword kw">else</span> <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;server list contains non-server: #{server.class}&quot;</span>&#x000A;50: <span class="ruby-keyword kw">end</span>&#x000A;51: <span class="ruby-keyword kw">end</span>&#x000A;52: <span class="ruby-keyword kw">self</span>&#x000A;53: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000064'>
+ <a name='M000064'> </a>
+ <div class='synopsis'>
+ <span class='name'>flatten</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns an array of all servers in the list, with dynamic server records
+ expanded. The result is an array of distinct server records (duplicates are
+ removed from the result).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000064-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000064-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 65</span>&#x000A;65: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">flatten</span>&#x000A;66: <span class="ruby-identifier">result</span> = <span class="ruby-ivar">@list</span>.<span class="ruby-identifier">inject</span>([]) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">aggregator</span>, <span class="ruby-identifier">server</span><span class="ruby-operator">|</span>&#x000A;67: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">server</span>&#x000A;68: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">Server</span> <span class="ruby-keyword kw">then</span> <span class="ruby-identifier">aggregator</span>.<span class="ruby-identifier">push</span>(<span class="ruby-identifier">server</span>)&#x000A;69: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">DynamicServer</span> <span class="ruby-keyword kw">then</span> <span class="ruby-identifier">aggregator</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">server</span>)&#x000A;70: <span class="ruby-keyword kw">else</span> <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;server list contains non-server: #{server.class}&quot;</span>&#x000A;71: <span class="ruby-keyword kw">end</span>&#x000A;72: <span class="ruby-keyword kw">end</span>&#x000A;73: &#x000A;74: <span class="ruby-identifier">result</span>.<span class="ruby-identifier">uniq</span>&#x000A;75: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000063'>
+ <a name='M000063'> </a>
+ <div class='synopsis'>
+ <span class='name'>select</span>
+ <span class='arguments'>() {|i| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Works exactly as Enumerable#select, but returns the result as a new <a
+ href="ServerList.html">ServerList</a> instance.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000063-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000063-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/server_list.rb, line 57</span>&#x000A;57: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">select</span>&#x000A;58: <span class="ruby-identifier">subset</span> = <span class="ruby-ivar">@list</span>.<span class="ruby-identifier">select</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">i</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">i</span> }&#x000A;59: <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">subset</span>)&#x000A;60: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000065'>
+ <a name='M000065'> </a>
+ <div class='synopsis'>
+ <span class='name'>to_ary</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Alias for <a href="ServerList.html#M000064">flatten</a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/Session.html b/classes/Net/SSH/Multi/Session.html
new file mode 100644
index 0000000..e0ba392
--- /dev/null
+++ b/classes/Net/SSH/Multi/Session.html
@@ -0,0 +1,560 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::Session [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::Session
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ Represents a collection of connections to various servers. It provides an
+ interface for organizing the connections (<a
+ href="Session.html#M000067">group</a>), as well as a way to scope commands
+ to a subset of all connections (<a href="Session.html#M000072">with</a>).
+ You can also provide a default gateway connection that servers should use
+ when connecting (<a href="Session.html#M000068">via</a>). It exposes an
+ interface similar to Net::SSH::Connection::Session for opening <a
+ href="../../SSH.html">SSH</a> channels and executing commands, allowing for
+ these operations to be done in parallel across multiple connections.
+ </p>
+ <pre>Net::SSH::Multi.start do |session|&#x000A; # access servers via a gateway&#x000A; session.via 'gateway', 'gateway-user'&#x000A;&#x000A; # define the servers we want to use&#x000A; session.use 'user1@host1'&#x000A; session.use 'user2@host2'&#x000A;&#x000A; # define servers in groups for more granular access&#x000A; session.group :app do&#x000A; session.use 'user@app1'&#x000A; session.use 'user@app2'&#x000A; end&#x000A;&#x000A; # execute commands on all servers&#x000A; session.exec &quot;uptime&quot;&#x000A;&#x000A; # execute commands on a subset of servers&#x000A; session.with(:app).exec &quot;hostname&quot;&#x000A;&#x000A; # run the aggregated event loop&#x000A; session.loop&#x000A;end</pre>
+ <p>
+ Note that connections are established lazily, as soon as they are needed.
+ You can force the connections to be opened immediately, though, using the
+ connect! method.
+ </p>
+ <h2>Concurrent Connection Limiting</h2>
+ <p>
+ Sometimes you may be dealing with a large number of servers, and if you try
+ to have connections open to all of them simultaneously you&#8217;ll run
+ into open file handle limitations and such. If this happens to you, you can
+ set the concurrent_connections property of the session. <a
+ href="../Multi.html">Net::SSH::Multi</a> will then ensure that no more than
+ this number of connections are ever open simultaneously.
+ </p>
+ <pre>Net::SSH::Multi.start(:concurrent_connections =&gt; 5) do |session|&#x000A; # ...&#x000A;end</pre>
+ <p>
+ Opening channels and executing commands will still work exactly as before,
+ but <a href="../Multi.html">Net::SSH::Multi</a> will transparently close
+ finished connections and open pending ones.
+ </p>
+ <h2>Controlling Connection Errors</h2>
+ <p>
+ By default, <a href="../Multi.html">Net::SSH::Multi</a> will raise an
+ exception if a connection error occurs when connecting to a server. This
+ will typically bubble up and abort the entire connection process.
+ Sometimes, however, you might wish to ignore connection errors, for
+ instance when starting a daemon on a large number of boxes and you know
+ that some of the boxes are going to be unavailable.
+ </p>
+ <p>
+ To do this, simply set the on_error property of the session to :ignore (or
+ to :warn, if you want a warning message when a connection attempt fails):
+ </p>
+ <pre>Net::SSH::Multi.start(:on_error =&gt; :ignore) do |session|&#x000A; # ...&#x000A;end</pre>
+ <p>
+ The default is :fail, which causes the exception to bubble up.
+ Additionally, you can specify a Proc object as the value for on_error,
+ which will be invoked with the server in question if the connection attempt
+ fails. You can force the connection attempt to retry by throwing the :go
+ symbol, with :retry as the payload, or force the exception to be reraised
+ by throwing :go with :raise as the payload:
+ </p>
+ <pre>handler = Proc.new do |server|&#x000A; server[:connection_attempts] ||= 0&#x000A; if server[:connection_attempts] &lt; 3&#x000A; server[:connection_attempts] += 1&#x000A; throw :go, :retry&#x000A; else&#x000A; throw :go, :raise&#x000A; end&#x000A;end&#x000A;&#x000A;Net::SSH::Multi.start(:on_error =&gt; handler) do |session|&#x000A; # ...&#x000A;end</pre>
+ <p>
+ Any other thrown value (or no thrown value at all) will result in the
+ failure being ignored.
+ </p>
+ <h2>Lazily Evaluated <a href="Server.html">Server</a> Definitions</h2>
+ <p>
+ Sometimes you might be dealing with an environment where you don&#8217;t
+ know the names or addresses of the servers until runtime. You can certainly
+ dynamically build server names and pass them to <a
+ href="Session.html#M000069">use</a>, but if the operation to determine the
+ server names is expensive, you might want to defer it until the server is
+ actually needed (especially if the logic of your program is such that you
+ might not even need to connect to that server every time the program runs).
+ </p>
+ <p>
+ You can do this by passing a block to <a
+ href="Session.html#M000069">use</a>:
+ </p>
+ <pre>session.use do |opt|&#x000A; lookup_ip_address_of_remote_host&#x000A;end</pre>
+ <p>
+ See <a href="Session.html#M000069">use</a> for more information about this
+ usage.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000066">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000074">close</a></li>
+ <li><a href="#M000067">group</a></li>
+ <li><a href="#M000075">loop</a></li>
+ <li><a href="#M000076">loop_forever</a></li>
+ <li><a href="#M000073">on</a></li>
+ <li><a href="#M000077">process</a></li>
+ <li><a href="#M000070">servers</a></li>
+ <li><a href="#M000071">servers_for</a></li>
+ <li><a href="#M000069">use</a></li>
+ <li><a href="#M000068">via</a></li>
+ <li><a href="#M000072">with</a></li>
+ </ol>
+ </div>
+ <div id='context'>
+ <div id='includes'>
+ <h2>Included modules</h2>
+ <ol>
+ <li><a href="SessionActions.html">SessionActions</a></li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>concurrent_connections</td>
+ <td class='context-item-value'>[RW]</td>
+ <td class='context-item-desc'>
+
+ The number of allowed concurrent connections. No more than this number of
+ sessions will be open at any given time.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>default_gateway</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The default Net::SSH::Gateway instance to use to connect to the servers. If
+ <tt>nil</tt>, no default gateway will be used.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>default_user</td>
+ <td class='context-item-value'>[RW]</td>
+ <td class='context-item-desc'>
+
+ The default user name to use when connecting to a server. If a user name is
+ not given for a particular server, this value will be used. It defaults to
+ ENV[&#8216;USER&#8217;] || ENV[&#8216;USERNAME&#8217;], or
+ &#8220;unknown&#8221; if neither of those are set.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>groups</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The hash of group definitions, mapping each group name to a corresponding
+ <a href="ServerList.html">Net::SSH::Multi::ServerList</a>.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>on_error</td>
+ <td class='context-item-value'>[RW]</td>
+ <td class='context-item-desc'>
+
+ How connection errors should be handled. This defaults to :fail, but may be
+ set to :ignore if connection errors should be ignored, or :warn if
+ connection errors should cause a warning.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>server_list</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The <a href="ServerList.html">Net::SSH::Multi::ServerList</a> managed by
+ this session.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000066'>
+ <a name='M000066'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(options={})</span>
+ </div>
+ <div class='description'>
+ <p>
+ Creates a new <a href="Session.html">Net::SSH::Multi::Session</a> instance.
+ Initially, it contains no server definitions, no group definitions, and no
+ default gateway.
+ </p>
+ <p>
+ You can set the concurrent_connections property in the options. Setting it
+ to <tt>nil</tt> (the default) will cause <a
+ href="../Multi.html">Net::SSH::Multi</a> to ignore any concurrent
+ connection limit and allow all defined sessions to be open simultaneously.
+ Setting it to an integer will cause <a
+ href="../Multi.html">Net::SSH::Multi</a> to allow no more than that number
+ of concurrently open sessions, opening subsequent sessions only when other
+ sessions finish and close.
+ </p>
+ <pre>Net::SSH::Multi.start(:concurrent_connections =&gt; 10) do |session|&#x000A; session.use ...&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000066-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000066-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 171</span>&#x000A;171: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">options</span>={})&#x000A;172: <span class="ruby-ivar">@server_list</span> = <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span>&#x000A;173: <span class="ruby-ivar">@groups</span> = <span class="ruby-constant">Hash</span>.<span class="ruby-identifier">new</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">h</span>,<span class="ruby-identifier">k</span><span class="ruby-operator">|</span> <span class="ruby-identifier">h</span>[<span class="ruby-identifier">k</span>] = <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span> }&#x000A;174: <span class="ruby-ivar">@gateway</span> = <span class="ruby-keyword kw">nil</span>&#x000A;175: <span class="ruby-ivar">@open_groups</span> = []&#x000A;176: <span class="ruby-ivar">@connect_threads</span> = []&#x000A;177: <span class="ruby-ivar">@on_error</span> = <span class="ruby-identifier">:fail</span>&#x000A;178: <span class="ruby-ivar">@default_user</span> = <span class="ruby-constant">ENV</span>[<span class="ruby-value str">'USER'</span>] <span class="ruby-operator">||</span> <span class="ruby-constant">ENV</span>[<span class="ruby-value str">'USERNAME'</span>] <span class="ruby-operator">||</span> <span class="ruby-value str">&quot;unknown&quot;</span>&#x000A;179: &#x000A;180: <span class="ruby-ivar">@open_connections</span> = <span class="ruby-value">0</span>&#x000A;181: <span class="ruby-ivar">@pending_sessions</span> = []&#x000A;182: <span class="ruby-ivar">@session_mutex</span> = <span class="ruby-constant">Mutex</span>.<span class="ruby-identifier">new</span>&#x000A;183: &#x000A;184: <span class="ruby-identifier">options</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">opt</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">send</span>(<span class="ruby-node">&quot;#{opt}=&quot;</span>, <span class="ruby-identifier">value</span>) }&#x000A;185: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000074'>
+ <a name='M000074'> </a>
+ <div class='synopsis'>
+ <span class='name'>close</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Closes the multi-session by shutting down all open server sessions, and the
+ default gateway (if one was specified using <a
+ href="Session.html#M000068">via</a>). Note that other gateway connections
+ (e.g., those passed to <a href="Session.html#M000069">use</a> directly)
+ will <em>not</em> be closed by this method, and must be managed externally.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000074-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000074-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 402</span>&#x000A;402: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">close</span>&#x000A;403: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">close_channels</span> }&#x000A;404: <span class="ruby-identifier">loop</span>(<span class="ruby-value">0</span>) { <span class="ruby-identifier">busy?</span>(<span class="ruby-keyword kw">true</span>) }&#x000A;405: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">close</span> }&#x000A;406: <span class="ruby-identifier">default_gateway</span>.<span class="ruby-identifier">shutdown!</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">default_gateway</span>&#x000A;407: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000067'>
+ <a name='M000067'> </a>
+ <div class='synopsis'>
+ <span class='name'>group</span>
+ <span class='arguments'>(*args) {|self| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ At its simplest, this associates a named group with a server definition. It
+ can be used in either of two ways:
+ </p>
+ <p>
+ First, you can use it to associate a group (or array of groups) with a
+ server definition (or array of server definitions). The server definitions
+ must already exist in the server_list array (typically by calling <a
+ href="Session.html#M000069">use</a>):
+ </p>
+ <pre>server1 = session.use('host1', 'user1')&#x000A;server2 = session.use('host2', 'user2')&#x000A;session.group :app =&gt; server1, :web =&gt; server2&#x000A;session.group :staging =&gt; [server1, server2]&#x000A;session.group %w(xen linux) =&gt; server2&#x000A;session.group %w(rackspace backup) =&gt; [server1, server2]</pre>
+ <p>
+ Secondly, instead of a mapping of groups to servers, you can just provide a
+ list of group names, and then a block. Inside the block, any calls to <a
+ href="Session.html#M000069">use</a> will automatically associate the new
+ server definition with those groups. You can nest <a
+ href="Session.html#M000067">group</a> calls, too, which will aggregate the
+ group definitions.
+ </p>
+ <pre>session.group :rackspace, :backup do&#x000A; session.use 'host1', 'user1'&#x000A; session.group :xen do&#x000A; session.use 'host2', 'user2'&#x000A; end&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000067-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000067-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 213</span>&#x000A;213: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">group</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">args</span>)&#x000A;214: <span class="ruby-identifier">mapping</span> = <span class="ruby-identifier">args</span>.<span class="ruby-identifier">last</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">?</span> <span class="ruby-identifier">args</span>.<span class="ruby-identifier">pop</span> <span class="ruby-operator">:</span> {}&#x000A;215: &#x000A;216: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">mapping</span>.<span class="ruby-identifier">any?</span> <span class="ruby-operator">&amp;&amp;</span> <span class="ruby-identifier">block_given?</span>&#x000A;217: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">&quot;must provide group mapping OR block, not both&quot;</span>&#x000A;218: <span class="ruby-keyword kw">elsif</span> <span class="ruby-identifier">block_given?</span>&#x000A;219: <span class="ruby-keyword kw">begin</span>&#x000A;220: <span class="ruby-identifier">saved_groups</span> = <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">dup</span>&#x000A;221: <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">args</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">a</span><span class="ruby-operator">|</span> <span class="ruby-identifier">a</span>.<span class="ruby-identifier">to_sym</span> }).<span class="ruby-identifier">uniq!</span>&#x000A;222: <span class="ruby-keyword kw">yield</span> <span class="ruby-keyword kw">self</span>&#x000A;223: <span class="ruby-keyword kw">ensure</span>&#x000A;224: <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">replace</span>(<span class="ruby-identifier">saved_groups</span>)&#x000A;225: <span class="ruby-keyword kw">end</span>&#x000A;226: <span class="ruby-keyword kw">else</span>&#x000A;227: <span class="ruby-identifier">mapping</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">key</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span>&#x000A;228: (<span class="ruby-identifier">open_groups</span> <span class="ruby-operator">+</span> <span class="ruby-constant">Array</span>(<span class="ruby-identifier">key</span>)).<span class="ruby-identifier">uniq</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">grp</span><span class="ruby-operator">|</span>&#x000A;229: <span class="ruby-identifier">groups</span>[<span class="ruby-identifier">grp</span>.<span class="ruby-identifier">to_sym</span>].<span class="ruby-identifier">concat</span>(<span class="ruby-constant">Array</span>(<span class="ruby-identifier">value</span>))&#x000A;230: <span class="ruby-keyword kw">end</span>&#x000A;231: <span class="ruby-keyword kw">end</span>&#x000A;232: <span class="ruby-keyword kw">end</span>&#x000A;233: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000075'>
+ <a name='M000075'> </a>
+ <div class='synopsis'>
+ <span class='name'>loop</span>
+ <span class='arguments'>(wait=nil, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Run the aggregated event loop for all open server sessions, until the given
+ block returns <tt>false</tt>. If no block is given, the loop will run for
+ as long as busy? returns <tt>true</tt> (in other words, for as long as
+ there are any (non-invisible) channels open).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000075-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000075-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 415</span>&#x000A;415: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">loop</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword kw">nil</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;416: <span class="ruby-identifier">running</span> = <span class="ruby-identifier">block</span> <span class="ruby-operator">||</span> <span class="ruby-constant">Proc</span>.<span class="ruby-identifier">new</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">c</span><span class="ruby-operator">|</span> <span class="ruby-identifier">busy?</span> }&#x000A;417: <span class="ruby-identifier">loop_forever</span> { <span class="ruby-keyword kw">break</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">running</span>) }&#x000A;418: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000076'>
+ <a name='M000076'> </a>
+ <div class='synopsis'>
+ <span class='name'>loop_forever</span>
+ <span class='arguments'>(wait=nil, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Alias for <a href="Session.html#M000075">loop</a>
+ </p>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000073'>
+ <a name='M000073'> </a>
+ <div class='synopsis'>
+ <span class='name'>on</span>
+ <span class='arguments'>(*servers) {|subsession if block_given?| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Works as <a href="Session.html#M000072">with</a>, but for specific servers
+ rather than groups. It will return a new subsession (<a
+ href="Subsession.html">Net::SSH::Multi::Subsession</a>) consisting of the
+ given servers. (Note that it requires that the servers in question have
+ been created via calls to <a href="Session.html#M000069">use</a> on this
+ session object, or things will not work quite right.) If a block is given,
+ the new subsession will also be yielded to the block.
+ </p>
+ <pre>srv1 = session.use('host1', 'user')&#x000A;srv2 = session.use('host2', 'user')&#x000A;# ...&#x000A;session.on(srv1, srv2).exec('hostname')</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000073-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000073-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 392</span>&#x000A;392: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">on</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">servers</span>)&#x000A;393: <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">servers</span>)&#x000A;394: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>&#x000A;395: <span class="ruby-identifier">subsession</span>&#x000A;396: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000077'>
+ <a name='M000077'> </a>
+ <div class='synopsis'>
+ <span class='name'>process</span>
+ <span class='arguments'>(wait=nil, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Run a single iteration of the aggregated event loop for all open server
+ sessions. The <tt>wait</tt> parameter indicates how long to wait for an
+ event to appear on any of the different sessions; <tt>nil</tt> (the
+ default) means &#8220;wait forever&#8221;. If the block is given, then it
+ will be used to determine whether <a
+ href="Session.html#M000077">process</a> returns <tt>true</tt> (the block
+ did not return <tt>false</tt>), or <tt>false</tt> (the block returned
+ <tt>false</tt>).
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000077-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000077-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 426</span>&#x000A;426: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword kw">nil</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;427: <span class="ruby-identifier">realize_pending_connections!</span>&#x000A;428: <span class="ruby-identifier">wait</span> = <span class="ruby-ivar">@connect_threads</span>.<span class="ruby-identifier">any?</span> <span class="ruby-value">? </span><span class="ruby-value">0</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">wait</span>&#x000A;429: &#x000A;430: <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">false</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">preprocess</span>(<span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;431: &#x000A;432: <span class="ruby-identifier">readers</span> = <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">s</span>.<span class="ruby-identifier">readers</span> }.<span class="ruby-identifier">flatten</span>&#x000A;433: <span class="ruby-identifier">writers</span> = <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">s</span><span class="ruby-operator">|</span> <span class="ruby-identifier">s</span>.<span class="ruby-identifier">writers</span> }.<span class="ruby-identifier">flatten</span>&#x000A;434: &#x000A;435: <span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>, = <span class="ruby-constant">IO</span>.<span class="ruby-identifier">select</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>, <span class="ruby-keyword kw">nil</span>, <span class="ruby-identifier">wait</span>)&#x000A;436: &#x000A;437: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">readers</span>&#x000A;438: <span class="ruby-keyword kw">return</span> <span class="ruby-identifier">postprocess</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>)&#x000A;439: <span class="ruby-keyword kw">else</span>&#x000A;440: <span class="ruby-keyword kw">return</span> <span class="ruby-keyword kw">true</span>&#x000A;441: <span class="ruby-keyword kw">end</span>&#x000A;442: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000070'>
+ <a name='M000070'> </a>
+ <div class='synopsis'>
+ <span class='name'>servers</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Essentially an alias for <a href="Session.html#M000071">servers_for</a>
+ without any arguments. This is used primarily to satistfy the expectations
+ of the <a href="SessionActions.html">Net::SSH::Multi::SessionActions</a>
+ module.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000070-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000070-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 293</span>&#x000A;293: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">servers</span>&#x000A;294: <span class="ruby-identifier">servers_for</span>&#x000A;295: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000071'>
+ <a name='M000071'> </a>
+ <div class='synopsis'>
+ <span class='name'>servers_for</span>
+ <span class='arguments'>(*criteria)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the set of servers that match the given criteria. It can be used in
+ any (or all) of three ways.
+ </p>
+ <p>
+ First, you can omit any arguments. In this case, the full list of servers
+ will be returned.
+ </p>
+ <pre>all = session.servers_for</pre>
+ <p>
+ Second, you can simply specify a list of group names. All servers in all
+ named groups will be returned. If a server belongs to multiple matching
+ groups, then it will appear only once in the list (the resulting list will
+ contain only unique servers).
+ </p>
+ <pre>servers = session.servers_for(:app, :db)</pre>
+ <p>
+ Last, you can specify a hash with group names as keys, and property
+ constraints as the values. These property constraints are either
+ &#8220;only&#8221; constraints (which restrict the set of servers to
+ &#8220;only&#8221; those that match the given properties) or
+ &#8220;except&#8221; constraints (which restrict the set of servers to
+ those whose properties do <em>not</em> match). Properties are described
+ when the server is defined (via the :properties key):
+ </p>
+ <pre>session.group :db do&#x000A; session.use 'dbmain', 'user', :properties =&gt; { :primary =&gt; true }&#x000A; session.use 'dbslave', 'user2'&#x000A; session.use 'dbslve2', 'user2'&#x000A;end&#x000A;&#x000A;# return ONLY on the servers in the :db group which have the :primary&#x000A;# property set to true.&#x000A;primary = session.servers_for(:db =&gt; { :only =&gt; { :primary =&gt; true } })</pre>
+ <p>
+ You can, naturally, combine these methods:
+ </p>
+ <pre># all servers in :app and :web, and all servers in :db with the&#x000A;# :primary property set to true&#x000A;servers = session.servers_for(:app, :web, :db =&gt; { :only =&gt; { :primary =&gt; true } })</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000071-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000071-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 334</span>&#x000A;334: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">servers_for</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">criteria</span>)&#x000A;335: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">empty?</span>&#x000A;336: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">flatten</span>&#x000A;337: <span class="ruby-keyword kw">else</span>&#x000A;338: <span class="ruby-comment cmt"># normalize the criteria list, so that every entry is a key to a</span>&#x000A;339: <span class="ruby-comment cmt"># criteria hash (possibly empty).</span>&#x000A;340: <span class="ruby-identifier">criteria</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>({}) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">hash</span>, <span class="ruby-identifier">entry</span><span class="ruby-operator">|</span>&#x000A;341: <span class="ruby-keyword kw">case</span> <span class="ruby-identifier">entry</span>&#x000A;342: <span class="ruby-keyword kw">when</span> <span class="ruby-constant">Hash</span> <span class="ruby-keyword kw">then</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">entry</span>)&#x000A;343: <span class="ruby-keyword kw">else</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">entry</span> =<span class="ruby-operator">&gt;</span> {})&#x000A;344: <span class="ruby-keyword kw">end</span>&#x000A;345: <span class="ruby-keyword kw">end</span>&#x000A;346: &#x000A;347: <span class="ruby-identifier">list</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>([]) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">aggregator</span>, (<span class="ruby-identifier">group</span>, <span class="ruby-identifier">properties</span>)<span class="ruby-operator">|</span>&#x000A;348: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;the value for any group must be a Hash, but got a #{properties.class} for #{group.inspect}&quot;</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">properties</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>)&#x000A;349: <span class="ruby-identifier">bad_keys</span> = <span class="ruby-identifier">properties</span>.<span class="ruby-identifier">keys</span> <span class="ruby-operator">-</span> [<span class="ruby-identifier">:only</span>, <span class="ruby-identifier">:except</span>]&#x000A;350: <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">&quot;unknown constraint(s) #{bad_keys.inspect} for #{group.inspect}&quot;</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">bad_keys</span>.<span class="ruby-identifier">empty?</span>&#x000A;351: &#x000A;352: <span class="ruby-identifier">servers</span> = <span class="ruby-identifier">groups</span>[<span class="ruby-identifier">group</span>].<span class="ruby-identifier">select</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span>&#x000A;353: (<span class="ruby-identifier">properties</span>[<span class="ruby-identifier">:only</span>] <span class="ruby-operator">||</span> {}).<span class="ruby-identifier">all?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">prop</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>[<span class="ruby-identifier">prop</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">value</span> } <span class="ruby-operator">&amp;&amp;</span>&#x000A;354: <span class="ruby-operator">!</span>(<span class="ruby-identifier">properties</span>[<span class="ruby-identifier">:except</span>] <span class="ruby-operator">||</span> {}).<span class="ruby-identifier">any?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">prop</span>, <span class="ruby-identifier">value</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>[<span class="ruby-identifier">prop</span>] <span class="ruby-operator">==</span> <span class="ruby-identifier">value</span> }&#x000A;355: <span class="ruby-keyword kw">end</span>&#x000A;356: &#x000A;357: <span class="ruby-identifier">aggregator</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">servers</span>)&#x000A;358: <span class="ruby-keyword kw">end</span>&#x000A;359: &#x000A;360: <span class="ruby-identifier">list</span>.<span class="ruby-identifier">uniq</span>&#x000A;361: <span class="ruby-keyword kw">end</span>&#x000A;362: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000069'>
+ <a name='M000069'> </a>
+ <div class='synopsis'>
+ <span class='name'>use</span>
+ <span class='arguments'>(*hosts, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Defines a new server definition, to be managed by this session. The server
+ is at the given <tt>host</tt>, and will be connected to as the given
+ <tt>user</tt>. The other options are passed as-is to the <a
+ href="../../SSH.html">Net::SSH</a> session constructor.
+ </p>
+ <p>
+ If a default gateway has been specified previously (with <a
+ href="Session.html#M000068">via</a>) it will be passed to the new server
+ definition. You can override this by passing a different Net::SSH::Gateway
+ instance (or <tt>nil</tt>) with the :via key in the <tt>options</tt>.
+ </p>
+ <pre>session.use 'host'&#x000A;session.use 'user@host2', :via =&gt; nil&#x000A;session.use 'host3', :user =&gt; &quot;user3&quot;, :via =&gt; Net::SSH::Gateway.new('gateway.host', 'user')</pre>
+ <p>
+ If only a single host is given, the new server instance is returned. You
+ can give multiple hosts at a time, though, in which case an array of server
+ instances will be returned.
+ </p>
+ <pre>server1, server2 = session.use &quot;host1&quot;, &quot;host2&quot;</pre>
+ <p>
+ If given a block, this will save the block as a <a
+ href="DynamicServer.html">Net::SSH::Multi::DynamicServer</a> definition, to
+ be evaluated lazily the first time the server is needed. The block will
+ recive any options hash given to <a href="Session.html#M000069">use</a>,
+ and should return <tt>nil</tt> (if no servers are to be added), a String or
+ an array of Strings (to be interpreted as a connection specification), or a
+ <a href="Server.html">Server</a> or an array of Servers.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000069-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000069-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 274</span>&#x000A;274: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">use</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">hosts</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;275: <span class="ruby-identifier">options</span> = <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">last</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>) <span class="ruby-operator">?</span> <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">pop</span> <span class="ruby-operator">:</span> {}&#x000A;276: <span class="ruby-identifier">options</span> = { <span class="ruby-identifier">:via</span> =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">default_gateway</span> }.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">options</span>)&#x000A;277: &#x000A;278: <span class="ruby-identifier">results</span> = <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">map</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">host</span><span class="ruby-operator">|</span>&#x000A;279: <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">add</span>(<span class="ruby-constant">Server</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">host</span>, <span class="ruby-identifier">options</span>))&#x000A;280: <span class="ruby-keyword kw">end</span>&#x000A;281: &#x000A;282: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block</span>&#x000A;283: <span class="ruby-identifier">results</span> <span class="ruby-operator">&lt;&lt;</span> <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">add</span>(<span class="ruby-constant">DynamicServer</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">block</span>))&#x000A;284: <span class="ruby-keyword kw">end</span>&#x000A;285: &#x000A;286: <span class="ruby-identifier">group</span> [] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">results</span>&#x000A;287: <span class="ruby-identifier">results</span>.<span class="ruby-identifier">length</span> <span class="ruby-operator">&gt;</span> <span class="ruby-value">1</span> <span class="ruby-operator">?</span> <span class="ruby-identifier">results</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">results</span>.<span class="ruby-identifier">first</span>&#x000A;288: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000068'>
+ <a name='M000068'> </a>
+ <div class='synopsis'>
+ <span class='name'>via</span>
+ <span class='arguments'>(host, user, options={})</span>
+ </div>
+ <div class='description'>
+ <p>
+ Sets up a default gateway to use when establishing connections to servers.
+ Note that any servers defined prior to this invocation will not use the
+ default gateway; it only affects servers defined subsequently.
+ </p>
+ <pre>session.via 'gateway.host', 'user'</pre>
+ <p>
+ You may override the default gateway on a per-server basis by passing the
+ :via key to the <a href="Session.html#M000069">use</a> method; see <a
+ href="Session.html#M000069">use</a> for details.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000068-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000068-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 243</span>&#x000A;243: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">via</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">user</span>, <span class="ruby-identifier">options</span>={})&#x000A;244: <span class="ruby-ivar">@default_gateway</span> = <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">SSH</span><span class="ruby-operator">::</span><span class="ruby-constant">Gateway</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">host</span>, <span class="ruby-identifier">user</span>, <span class="ruby-identifier">options</span>)&#x000A;245: <span class="ruby-keyword kw">self</span>&#x000A;246: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000072'>
+ <a name='M000072'> </a>
+ <div class='synopsis'>
+ <span class='name'>with</span>
+ <span class='arguments'>(*groups) {|subsession if block_given?| ...}</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns a new <a href="Subsession.html">Net::SSH::Multi::Subsession</a>
+ instance consisting of the servers that meet the given criteria. If a block
+ is given, the subsession will be yielded to it. See <a
+ href="Session.html#M000071">servers_for</a> for a discussion of how these
+ criteria are interpreted.
+ </p>
+ <pre>session.with(:app).exec('hostname')&#x000A;&#x000A;session.with(:app, :db =&gt; { :primary =&gt; true }) do |s|&#x000A; s.exec 'date'&#x000A; s.exec 'uptime'&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000072-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000072-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session.rb, line 375</span>&#x000A;375: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">with</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">groups</span>)&#x000A;376: <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword kw">self</span>, <span class="ruby-identifier">servers_for</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">groups</span>))&#x000A;377: <span class="ruby-keyword kw">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>&#x000A;378: <span class="ruby-identifier">subsession</span>&#x000A;379: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/SessionActions.html b/classes/Net/SSH/Multi/SessionActions.html
new file mode 100644
index 0000000..ad9a7b4
--- /dev/null
+++ b/classes/Net/SSH/Multi/SessionActions.html
@@ -0,0 +1,272 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::SessionActions [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Module</span>
+ Net::SSH::Multi::SessionActions
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/session_actions_rb.html">lib/net/ssh/multi/session_actions.rb</a>
+ </li>
+ </ol>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ This module represents the actions that are available on session
+ collections. Any class that includes this module needs only provide a
+ <tt>servers</tt> method that returns a list of <a
+ href="Server.html">Net::SSH::Multi::Server</a> instances, and the rest just
+ works. See <a href="Session.html">Net::SSH::Multi::Session</a> and <a
+ href="Subsession.html">Net::SSH::Multi::Subsession</a> for consumers of
+ this module.
+ </p>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000004">busy?</a></li>
+ <li><a href="#M000003">connect!</a></li>
+ <li><a href="#M000008">exec</a></li>
+ <li><a href="#M000002">master</a></li>
+ <li><a href="#M000007">open_channel</a></li>
+ <li><a href="#M000006">send_global_request</a></li>
+ <li><a href="#M000005">sessions</a></li>
+ </ol>
+ </div>
+ <div id='section'>
+ <div id='methods'>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000004'>
+ <a name='M000004'> </a>
+ <div class='synopsis'>
+ <span class='name'>busy?</span>
+ <span class='arguments'>(include_invisible=false)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns <tt>true</tt> if any server in the current container has an open <a
+ href="../../SSH.html">SSH</a> session that is currently processing any
+ channels. If <tt>include_invisible</tt> is <tt>false</tt> (the default)
+ then invisible channels (such as those created by port forwarding) will not
+ be counted; otherwise, they will be.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000004-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000004-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 29</span>&#x000A;29: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">busy?</span>(<span class="ruby-identifier">include_invisible</span>=<span class="ruby-keyword kw">false</span>)&#x000A;30: <span class="ruby-identifier">servers</span>.<span class="ruby-identifier">any?</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">busy?</span>(<span class="ruby-identifier">include_invisible</span>) }&#x000A;31: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000003'>
+ <a name='M000003'> </a>
+ <div class='synopsis'>
+ <span class='name'>connect!</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Connections are normally established lazily, as soon as they are needed.
+ This method forces all servers in the current container to have their
+ connections established immediately, blocking until the connections have
+ been made.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000003-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000003-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 20</span>&#x000A;20: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">connect!</span>&#x000A;21: <span class="ruby-identifier">sessions</span>&#x000A;22: <span class="ruby-keyword kw">self</span>&#x000A;23: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000008'>
+ <a name='M000008'> </a>
+ <div class='synopsis'>
+ <span class='name'>exec</span>
+ <span class='arguments'>(command, &amp;block)</span>
+ </div>
+ <div class='description'>
+ <p>
+ A convenience method for executing a command on multiple hosts and either
+ displaying or capturing the output. It opens a channel on all active
+ sessions (see <a href="SessionActions.html#M000007">open_channel</a> and
+ active_sessions), and then executes a command on each channel
+ (Net::SSH::Connection::Channel#exec).
+ </p>
+ <p>
+ If a block is given, it will be invoked whenever data is received across
+ the channel, with three arguments: the channel object, a symbol identifying
+ which output stream the data was received on (<tt>:stdout</tt> or
+ <tt>:stderr</tt>) and a string containing the data that was received:
+ </p>
+ <pre>session.exec(&quot;command&quot;) do |ch, stream, data|&#x000A; puts &quot;[#{ch[:host]} : #{stream}] #{data}&quot;&#x000A;end</pre>
+ <p>
+ If no block is given, all output will be written to +$stdout+ or +$stderr+,
+ as appropriate.
+ </p>
+ <p>
+ Note that <a href="SessionActions.html#M000008">exec</a> will also capture
+ the exit status of the process in the <tt>:exit_status</tt> property of
+ each channel. Since <a href="SessionActions.html#M000008">exec</a> returns
+ all of the channels in a <a
+ href="Channel.html">Net::SSH::Multi::Channel</a> object, you can check for
+ the exit status like this:
+ </p>
+ <pre>channel = session.exec(&quot;command&quot;) { ... }&#x000A;channel.wait&#x000A;&#x000A;if channel.any? { |c| c[:exit_status] != 0 }&#x000A; puts &quot;executing failed on at least one host!&quot;&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000008-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000008-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 119</span>&#x000A;119: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">exec</span>(<span class="ruby-identifier">command</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span>)&#x000A;120: <span class="ruby-identifier">open_channel</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">channel</span><span class="ruby-operator">|</span>&#x000A;121: <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">exec</span>(<span class="ruby-identifier">command</span>) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">ch</span>, <span class="ruby-identifier">success</span><span class="ruby-operator">|</span>&#x000A;122: <span class="ruby-identifier">raise</span> <span class="ruby-node">&quot;could not execute command: #{command.inspect} (#{ch[:host]})&quot;</span> <span class="ruby-keyword kw">unless</span> <span class="ruby-identifier">success</span>&#x000A;123: &#x000A;124: <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_data</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">ch</span>, <span class="ruby-identifier">data</span><span class="ruby-operator">|</span>&#x000A;125: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block</span>&#x000A;126: <span class="ruby-identifier">block</span>.<span class="ruby-identifier">call</span>(<span class="ruby-identifier">ch</span>, <span class="ruby-identifier">:stdout</span>, <span class="ruby-identifier">data</span>)&#x000A;127: <span class="ruby-keyword kw">else</span>&#x000A;128: <span class="ruby-identifier">data</span>.<span class="ruby-identifier">chomp</span>.<span class="ruby-identifier">each_line</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">line</span><span class="ruby-operator">|</span>&#x000A;129: <span class="ruby-identifier">$stdout</span>.<span class="ruby-identifier">puts</span>(<span class="ruby-node">&quot;[#{ch[:host]}] #{line}&quot;</span>)&#x000A;130: <span class="ruby-keyword kw">end</span>&#x000A;131: <span class="ruby-keyword kw">end</span>&#x000A;132: <span class="ruby-keyword kw">end</span>&#x000A;133: &#x000A;134: <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_extended_data</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">ch</span>, <span class="ruby-identifier">type</span>, <span class="ruby-identifier">data</span><span class="ruby-operator">|</span>&#x000A;135: <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block</span>&#x000A;136: <span class="ruby-identifier">block</span>.<span class="ruby-identifier">call</span>(<span class="ruby-identifier">ch</span>, <span class="ruby-identifier">:stderr</span>, <span class="ruby-identifier">data</span>)&#x000A;137: <span class="ruby-keyword kw">else</span>&#x000A;138: <span class="ruby-identifier">data</span>.<span class="ruby-identifier">chomp</span>.<span class="ruby-identifier">each_line</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">line</span><span class="ruby-operator">|</span>&#x000A;139: <span class="ruby-identifier">$stderr</span>.<span class="ruby-identifier">puts</span>(<span class="ruby-node">&quot;[#{ch[:host]}] #{line}&quot;</span>)&#x000A;140: <span class="ruby-keyword kw">end</span>&#x000A;141: <span class="ruby-keyword kw">end</span>&#x000A;142: <span class="ruby-keyword kw">end</span>&#x000A;143: &#x000A;144: <span class="ruby-identifier">channel</span>.<span class="ruby-identifier">on_request</span>(<span class="ruby-value str">&quot;exit-status&quot;</span>) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">ch</span>, <span class="ruby-identifier">data</span><span class="ruby-operator">|</span>&#x000A;145: <span class="ruby-identifier">ch</span>[<span class="ruby-identifier">:exit_status</span>] = <span class="ruby-identifier">data</span>.<span class="ruby-identifier">read_long</span>&#x000A;146: <span class="ruby-keyword kw">end</span>&#x000A;147: <span class="ruby-keyword kw">end</span>&#x000A;148: <span class="ruby-keyword kw">end</span>&#x000A;149: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000002'>
+ <a name='M000002'> </a>
+ <div class='synopsis'>
+ <span class='name'>master</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns the session that is the &#8220;master&#8221;. This defaults to
+ <tt>self</tt>, but classes that include this module may wish to change this
+ if they are subsessions that depend on a master session.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000002-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000002-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 12</span>&#x000A;12: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">master</span>&#x000A;13: <span class="ruby-keyword kw">self</span>&#x000A;14: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000007'>
+ <a name='M000007'> </a>
+ <div class='synopsis'>
+ <span class='name'>open_channel</span>
+ <span class='arguments'>(type=&quot;session&quot;, *extra, &amp;on_confirm)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Asks all sessions for all contained servers (see <a
+ href="SessionActions.html#M000005">sessions</a>) to open a new channel.
+ When each server responds, the <tt>on_confirm</tt> block will be invoked
+ with a single argument, the channel object for that server. This means that
+ the block will be invoked one time for each session.
+ </p>
+ <p>
+ All new channels will be collected and returned, aggregated into a new <a
+ href="Channel.html">Net::SSH::Multi::Channel</a> instance.
+ </p>
+ <p>
+ Note that the channels are &#8220;enhanced&#8221; slightly&#8212;they have
+ two properties set on them automatically, to make dealing with them in a
+ multi-session environment slightly easier:
+ </p>
+ <ul>
+ <li>:server => the <a href="Server.html">Net::SSH::Multi::Server</a> instance
+ that spawned the channel
+
+ </li>
+ <li>:host => the host name of the server
+
+ </li>
+ </ul>
+ <p>
+ Having access to these things lets you more easily report which host (e.g.)
+ data was received from:
+ </p>
+ <pre>session.open_channel do |channel|&#x000A; channel.exec &quot;command&quot; do |ch, success|&#x000A; ch.on_data do |ch, data|&#x000A; puts &quot;got data #{data} from #{ch[:host]}&quot;&#x000A; end&#x000A; end&#x000A;end</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000007-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000007-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 80</span>&#x000A;80: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">open_channel</span>(<span class="ruby-identifier">type</span>=<span class="ruby-value str">&quot;session&quot;</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extra</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">on_confirm</span>)&#x000A;81: <span class="ruby-identifier">channels</span> = <span class="ruby-identifier">sessions</span>.<span class="ruby-identifier">map</span> <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">ssh</span><span class="ruby-operator">|</span>&#x000A;82: <span class="ruby-identifier">ssh</span>.<span class="ruby-identifier">open_channel</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extra</span>) <span class="ruby-keyword kw">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">c</span><span class="ruby-operator">|</span>&#x000A;83: <span class="ruby-identifier">c</span>[<span class="ruby-identifier">:server</span>] = <span class="ruby-identifier">c</span>.<span class="ruby-identifier">connection</span>[<span class="ruby-identifier">:server</span>]&#x000A;84: <span class="ruby-identifier">c</span>[<span class="ruby-identifier">:host</span>] = <span class="ruby-identifier">c</span>.<span class="ruby-identifier">connection</span>[<span class="ruby-identifier">:server</span>].<span class="ruby-identifier">host</span>&#x000A;85: <span class="ruby-identifier">on_confirm</span>[<span class="ruby-identifier">c</span>] <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">on_confirm</span>&#x000A;86: <span class="ruby-keyword kw">end</span>&#x000A;87: <span class="ruby-keyword kw">end</span>&#x000A;88: <span class="ruby-constant">Multi</span><span class="ruby-operator">::</span><span class="ruby-constant">Channel</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">master</span>, <span class="ruby-identifier">channels</span>)&#x000A;89: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000006'>
+ <a name='M000006'> </a>
+ <div class='synopsis'>
+ <span class='name'>send_global_request</span>
+ <span class='arguments'>(type, *extra, &amp;callback)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Sends a global request to the sessions for all contained servers (see <a
+ href="SessionActions.html#M000005">sessions</a>). This can be used to
+ (e.g.) ping the remote servers to prevent them from timing out.
+ </p>
+ <pre>session.send_global_request(&quot;keep-alive@openssh.com&quot;)</pre>
+ <p>
+ If a block is given, it will be invoked when the server responds, with two
+ arguments: the <a href="../../SSH.html">Net::SSH</a> connection that is
+ responding, and a boolean indicating whether the request succeeded or not.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000006-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000006-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 50</span>&#x000A;50: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">send_global_request</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extra</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">callback</span>)&#x000A;51: <span class="ruby-identifier">sessions</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">ssh</span><span class="ruby-operator">|</span> <span class="ruby-identifier">ssh</span>.<span class="ruby-identifier">send_global_request</span>(<span class="ruby-identifier">type</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">extra</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">callback</span>) }&#x000A;52: <span class="ruby-keyword kw">self</span>&#x000A;53: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000005'>
+ <a name='M000005'> </a>
+ <div class='synopsis'>
+ <span class='name'>sessions</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns an array of all <a href="../../SSH.html">SSH</a> sessions, blocking
+ until all sessions have connected.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000005-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000005-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/session_actions.rb, line 35</span>&#x000A;35: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">sessions</span>&#x000A;36: <span class="ruby-identifier">threads</span> = <span class="ruby-identifier">servers</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-constant">Thread</span>.<span class="ruby-identifier">new</span> { <span class="ruby-identifier">server</span>.<span class="ruby-identifier">session</span>(<span class="ruby-keyword kw">true</span>) } <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">session</span>.<span class="ruby-identifier">nil?</span> }&#x000A;37: <span class="ruby-identifier">threads</span>.<span class="ruby-identifier">each</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">thread</span><span class="ruby-operator">|</span> <span class="ruby-identifier">thread</span>.<span class="ruby-identifier">join</span> <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">thread</span> }&#x000A;38: <span class="ruby-identifier">servers</span>.<span class="ruby-identifier">map</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span> <span class="ruby-identifier">server</span>.<span class="ruby-identifier">session</span> }.<span class="ruby-identifier">compact</span>&#x000A;39: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/Subsession.html b/classes/Net/SSH/Multi/Subsession.html
new file mode 100644
index 0000000..e6268a7
--- /dev/null
+++ b/classes/Net/SSH/Multi/Subsession.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::Subsession [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::Subsession
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/subsession_rb.html">lib/net/ssh/multi/subsession.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Object</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ A trivial class for representing a subset of servers. It is used internally
+ for restricting operations to a subset of all defined servers.
+ </p>
+ <pre>subsession = session.with(:app)&#x000A;subsession.exec(&quot;hostname&quot;)</pre>
+ </div>
+ <div id='method-list'>
+ <h2>Methods</h2>
+ <h3>public class</h3>
+ <ol>
+ <li><a href="#M000078">new</a></li>
+ </ol>
+ <h3>public instance</h3>
+ <ol>
+ <li><a href="#M000080">first</a></li>
+ <li><a href="#M000079">slice</a></li>
+ </ol>
+ </div>
+ <div id='context'>
+ <div id='includes'>
+ <h2>Included modules</h2>
+ <ol>
+ <li><a href="SessionActions.html">SessionActions</a></li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ <div id='attribute-list'>
+ <h2 class='section-bar'>Attributes</h2>
+ <div class='name-list'>
+ <table>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>master</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The master session that spawned this subsession.
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>servers</td>
+ <td class='context-item-value'>[R]</td>
+ <td class='context-item-desc'>
+
+ The list of servers that this subsession can operate on.
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id='methods'>
+ <h2>Public class methods</h2>
+ <div class='method public-class' id='method-M000078'>
+ <a name='M000078'> </a>
+ <div class='synopsis'>
+ <span class='name'>new</span>
+ <span class='arguments'>(master, server_list)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Create a new subsession of the given <tt>master</tt> session, that operates
+ on the given <tt>server_list</tt>.
+ </p>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000078-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000078-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/subsession.rb, line 22</span>&#x000A;22: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">master</span>, <span class="ruby-identifier">server_list</span>)&#x000A;23: <span class="ruby-ivar">@master</span> = <span class="ruby-identifier">master</span>&#x000A;24: <span class="ruby-ivar">@servers</span> = <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">uniq</span>&#x000A;25: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <h2>Public instance methods</h2>
+ <div class='method public-instance' id='method-M000080'>
+ <a name='M000080'> </a>
+ <div class='synopsis'>
+ <span class='name'>first</span>
+ <span class='arguments'>()</span>
+ </div>
+ <div class='description'>
+ <p>
+ Returns a new subsession that consists of only the first server in the
+ server list of the current subsession. This is just convenience for
+ slice(0):
+ </p>
+ <pre>s1 = subsession.first</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000080-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000080-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/subsession.rb, line 43</span>&#x000A;43: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">first</span>&#x000A;44: <span class="ruby-identifier">slice</span>(<span class="ruby-value">0</span>)&#x000A;45: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ <div class='method public-instance' id='method-M000079'>
+ <a name='M000079'> </a>
+ <div class='synopsis'>
+ <span class='name'>slice</span>
+ <span class='arguments'>(*args)</span>
+ </div>
+ <div class='description'>
+ <p>
+ Works as Array#slice, but returns a new subsession consisting of the given
+ slice of servers in this subsession. The new subsession will have the same
+ master session as this subsession does.
+ </p>
+ <pre>s1 = subsession.slice(0)&#x000A;s2 = subsession.slice(3, -1)&#x000A;s3 = subsession.slice(1..4)</pre>
+ </div>
+ <div class='source'>
+ <a class='source-toggle' href='#' onclick="toggleCode('M000079-source'); return false">
+ [show source]
+ </a>
+ <pre id='M000079-source'> <span class="ruby-comment cmt"># File lib/net/ssh/multi/subsession.rb, line 34</span>&#x000A;34: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">slice</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">args</span>)&#x000A;35: <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">master</span>, <span class="ruby-constant">Array</span>(<span class="ruby-identifier">servers</span>.<span class="ruby-identifier">slice</span>(<span class="ruby-operator">*</span><span class="ruby-identifier">args</span>)))&#x000A;36: <span class="ruby-keyword kw">end</span></pre>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/classes/Net/SSH/Multi/Version.html b/classes/Net/SSH/Multi/Version.html
new file mode 100644
index 0000000..3b9b8ad
--- /dev/null
+++ b/classes/Net/SSH/Multi/Version.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>: Net::SSH::Multi::Version [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='class' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>
+ <span class='type'>Class</span>
+ Net::SSH::Multi::Version
+ </h1>
+ <ol class='paths'>
+ <li>
+ <a href="../../../../files/lib/net/ssh/multi/version_rb.html">lib/net/ssh/multi/version.rb</a>
+ </li>
+ </ol>
+ <div class='parent'>
+ Parent:
+ <strong>Net::SSH::Version</strong>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <p>
+ A trivial class for representing the version of this library.
+ </p>
+ </div>
+ <div id='section'>
+ <div id='constants-list'>
+ <h2>Constants</h2>
+ <div class='name-list'>
+ <table summary='Constants'>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>MAJOR</td>
+ <td>=</td>
+ <td class='context-item-value'>1</td>
+ <td>&nbsp;</td>
+ <td class='context-item-desc'>
+
+ The major component of the library&#8217;s version
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>MINOR</td>
+ <td>=</td>
+ <td class='context-item-value'>1</td>
+ <td>&nbsp;</td>
+ <td class='context-item-desc'>
+
+ The minor component of the library&#8217;s version
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>TINY</td>
+ <td>=</td>
+ <td class='context-item-value'>0</td>
+ <td>&nbsp;</td>
+ <td class='context-item-desc'>
+
+ The tiny component of the library&#8217;s version
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>CURRENT</td>
+ <td>=</td>
+ <td class='context-item-value'>new(MAJOR, MINOR, TINY)</td>
+ <td>&nbsp;</td>
+ <td class='context-item-desc'>
+
+ The library&#8217;s version as a <a href="Version.html">Version</a>
+ instance
+ </td>
+ </tr>
+ <tr class='top-aligned-row context-row'>
+ <td class='context-item-name'>STRING</td>
+ <td>=</td>
+ <td class='context-item-value'>CURRENT.to_s</td>
+ <td>&nbsp;</td>
+ <td class='context-item-desc'>
+
+ The library&#8217;s version as a String instance
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/created.rid b/created.rid
new file mode 100644
index 0000000..2649bc5
--- /dev/null
+++ b/created.rid
@@ -0,0 +1 @@
+Sun, 03 Apr 2011 16:39:39 -0400
diff --git a/files/CHANGELOG_rdoc.html b/files/CHANGELOG_rdoc.html
new file mode 100644
index 0000000..f15739d
--- /dev/null
+++ b/files/CHANGELOG_rdoc.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: CHANGELOG.rdoc [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>CHANGELOG.rdoc</h1>
+ <div class='paths'>
+ CHANGELOG.rdoc
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <h3>1.1 / 3 Apr 2011</h3>
+ <ul>
+ <li>Rescue Timeout::Error so :on_error works as expected when server is
+ unavailable. [Joel Watson]
+
+ </li>
+ </ul>
+ <h3>1.0.1 / 1 Feb 2009</h3>
+ <ul>
+ <li>Remove redundant call to block_given? in Session#group [paddor]
+
+ </li>
+ <li>Add Channel#on_open_failed callback hook [Jamis Buck]
+
+ </li>
+ </ul>
+ <h3>1.0.0 / 1 May 2008</h3>
+ <ul>
+ <li>(no changes since the last preview release)
+
+ </li>
+ </ul>
+ <h3>1.0 Preview Release 2 (0.99.1) / 19 Apr 2008</h3>
+ <ul>
+ <li>Don&#8217;t try to select on closed IO streams [Jamis Buck]
+
+ </li>
+ </ul>
+ <h3>1.0 Preview Release 1 (0.99.0) / 10 Apr 2008</h3>
+ <ul>
+ <li>First release of <a
+ href="../classes/Net/SSH/Multi.html">Net::SSH::Multi</a>
+
+ </li>
+ </ul>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/README_rdoc.html b/files/README_rdoc.html
new file mode 100644
index 0000000..2902082
--- /dev/null
+++ b/files/README_rdoc.html
@@ -0,0 +1,156 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: README.rdoc [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <div class='name'>README.rdoc</div>
+ <div class='paths'>
+ README.rdoc
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='description'>
+ <h1><a href="../classes/Net/SSH/Multi.html">Net::SSH::Multi</a></h1>
+ <ul>
+ <li><a
+ href="http://net-ssh.rubyforge.org/multi">net-ssh.rubyforge.org/multi</a>
+
+ </li>
+ </ul>
+ <h2>DESCRIPTION:</h2>
+ <p>
+ <a href="../classes/Net/SSH/Multi.html">Net::SSH::Multi</a> is a library
+ for controlling multiple <a href="../classes/Net/SSH.html">Net::SSH</a>
+ connections via a single interface. It exposes an API similar to that of
+ Net::SSH::Connection::Session and Net::SSH::Connection::Channel, making it
+ simpler to adapt programs designed for single connections to be used with
+ multiple connections.
+ </p>
+ <p>
+ This library is particularly useful for automating repetitive tasks that
+ must be performed on multiple machines. It executes the commands in
+ parallel, and allows commands to be executed on subsets of servers (defined
+ by groups).
+ </p>
+ <h2>FEATURES:</h2>
+ <ul>
+ <li>Easily manage multiple connections
+
+ </li>
+ <li>Open channels, spawn processes, etc. on multiple connections in parallel
+
+ </li>
+ <li>Transparently limit concurrent connections when dealing with large numbers
+ of servers (Net::SSH::Multi::Session#concurrent_connections)
+
+ </li>
+ <li>Specify a default gateway machine through which connections should be
+ tunneled, or even specify a different gateway machine for each server
+
+ </li>
+ </ul>
+ <h2>SYNOPSIS:</h2>
+ <p>
+ In a nutshell:
+ </p>
+ <pre>require 'net/ssh/multi'&#x000A;&#x000A;Net::SSH::Multi.start do |session|&#x000A; # access servers via a gateway&#x000A; session.via 'gateway', 'gateway-user'&#x000A;&#x000A; # define the servers we want to use&#x000A; session.use 'user1@host1'&#x000A; session.use 'user2@host2'&#x000A;&#x000A; # define servers in groups for more granular access&#x000A; session.group :app do&#x000A; session.use 'user@app1'&#x000A; session.use 'user@app2'&#x000A; end&#x000A;&#x000A; # execute commands on all servers&#x000A; session.exec &quot;uptime&quot;&#x000A;&#x000A; # execute commands on a subset of servers&#x000A; session.with(:app).exec &quot;hostname&quot;&#x000A;&#x000A; # run the aggregated event loop&#x000A; session.loop&#x000A;end</pre>
+ <p>
+ See <a
+ href="../classes/Net/SSH/Multi/Session.html">Net::SSH::Multi::Session</a>
+ for more documentation.
+ </p>
+ <h2>REQUIREMENTS:</h2>
+ <ul>
+ <li>net-ssh (version 2)
+
+ </li>
+ <li>net-ssh-gateway
+
+ </li>
+ </ul>
+ <p>
+ If you want to run the tests or use any of the Rake tasks, you&#8217;ll
+ need:
+ </p>
+ <ul>
+ <li>Echoe (for the Rakefile)
+
+ </li>
+ <li>Mocha (for the tests)
+
+ </li>
+ </ul>
+ <h2>INSTALL:</h2>
+ <ul>
+ <li>gem install net-ssh-multi (might need sudo privileges)
+
+ </li>
+ </ul>
+ <h2>LICENSE:</h2>
+ <p>
+ (The MIT License)
+ </p>
+ <p>
+ Copyright &#169; 2008 Jamis Buck <jamis@37signals.com>
+ </p>
+ <p>
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ &#8216;Software&#8217;), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to the
+ following conditions:
+ </p>
+ <p>
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ </p>
+ <p>
+ THE SOFTWARE IS PROVIDED &#8216;AS IS&#8217;, WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
+ </p>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/channel_proxy_rb.html b/files/lib/net/ssh/multi/channel_proxy_rb.html
new file mode 100644
index 0000000..d81fa97
--- /dev/null
+++ b/files/lib/net/ssh/multi/channel_proxy_rb.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: channel_proxy.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>channel_proxy.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/channel_proxy.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/channel_rb.html b/files/lib/net/ssh/multi/channel_rb.html
new file mode 100644
index 0000000..47dadd8
--- /dev/null
+++ b/files/lib/net/ssh/multi/channel_rb.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: channel.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>channel.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/channel.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/dynamic_server_rb.html b/files/lib/net/ssh/multi/dynamic_server_rb.html
new file mode 100644
index 0000000..6fb1cd8
--- /dev/null
+++ b/files/lib/net/ssh/multi/dynamic_server_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: dynamic_server.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>dynamic_server.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/dynamic_server.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/multi/server</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/pending_connection_rb.html b/files/lib/net/ssh/multi/pending_connection_rb.html
new file mode 100644
index 0000000..47a3452
--- /dev/null
+++ b/files/lib/net/ssh/multi/pending_connection_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: pending_connection.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>pending_connection.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/pending_connection.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/multi/channel_proxy</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/server_list_rb.html b/files/lib/net/ssh/multi/server_list_rb.html
new file mode 100644
index 0000000..0ebda50
--- /dev/null
+++ b/files/lib/net/ssh/multi/server_list_rb.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: server_list.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>server_list.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/server_list.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/multi/server</li>
+ <li>net/ssh/multi/dynamic_server</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/server_rb.html b/files/lib/net/ssh/multi/server_rb.html
new file mode 100644
index 0000000..5f03c59
--- /dev/null
+++ b/files/lib/net/ssh/multi/server_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: server.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>server.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/server.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/session_actions_rb.html b/files/lib/net/ssh/multi/session_actions_rb.html
new file mode 100644
index 0000000..2244580
--- /dev/null
+++ b/files/lib/net/ssh/multi/session_actions_rb.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: session_actions.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>session_actions.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/session_actions.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/session_rb.html b/files/lib/net/ssh/multi/session_rb.html
new file mode 100644
index 0000000..bfc072e
--- /dev/null
+++ b/files/lib/net/ssh/multi/session_rb.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: session.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>session.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/session.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>thread</li>
+ <li>net/ssh/gateway</li>
+ <li>net/ssh/multi/server</li>
+ <li>net/ssh/multi/dynamic_server</li>
+ <li>net/ssh/multi/server_list</li>
+ <li>net/ssh/multi/channel</li>
+ <li>net/ssh/multi/pending_connection</li>
+ <li>net/ssh/multi/session_actions</li>
+ <li>net/ssh/multi/subsession</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/subsession_rb.html b/files/lib/net/ssh/multi/subsession_rb.html
new file mode 100644
index 0000000..0e2a9f3
--- /dev/null
+++ b/files/lib/net/ssh/multi/subsession_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: subsession.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>subsession.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/subsession.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/multi/session_actions</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi/version_rb.html b/files/lib/net/ssh/multi/version_rb.html
new file mode 100644
index 0000000..7a91902
--- /dev/null
+++ b/files/lib/net/ssh/multi/version_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: version.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>version.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi/version.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/version</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/files/lib/net/ssh/multi_rb.html b/files/lib/net/ssh/multi_rb.html
new file mode 100644
index 0000000..99bc554
--- /dev/null
+++ b/files/lib/net/ssh/multi_rb.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>File: multi.rb [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='../../../../rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <script type='text/javascript'>
+ //<![CDATA[
+ function popupCode(url) {
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
+ }
+
+ function toggleCode(id) {
+ var code = document.getElementById(id)
+
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
+ return true
+ }
+
+ // Make codeblocks hidden by default
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
+ //]]>
+ </script>
+ </head>
+ <body class='page'>
+ <div class='file' id='wrapper'>
+ <div class='header'>
+ <h1 class='name'>multi.rb</h1>
+ <div class='paths'>
+ lib/net/ssh/multi.rb
+ </div>
+ <div class='last-update'>
+ Last Update:
+ <span class='datetime'>2011-04-03 16:38:48 -0400</span>
+ </div>
+ </div>
+ <div id='content'>
+ <div id='text'>
+ <div id='context'>
+ <div id='requires'>
+ <h2>Required files</h2>
+ <ol>
+ <li>net/ssh/multi/session</li>
+ </ol>
+ </div>
+ </div>
+ <div id='section'>
+ </div>
+ </div>
+ </div>
+ <div id='footer-push'></div>
+ </div>
+ <div id='footer'>
+ <a href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
+ </div>
+ </body>
+</html>
diff --git a/fr_class_index.html b/fr_class_index.html
new file mode 100644
index 0000000..32489bb
--- /dev/null
+++ b/fr_class_index.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>Classes [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <base target='docwin'>
+ </head>
+ <body class='list'>
+ <div id='index'>
+ <h1>Classes</h1>
+ <ol class='classes' id='index-entries'>
+ <li><a href="classes/Net.html">Net</a>
+ <ol><li><a href="classes/Net/SSH.html"><span class="parent">Net::</span>SSH</a>
+ <ol><li><a href="classes/Net/SSH/Multi.html"><span class="parent">Net::SSH::</span>Multi</a>
+ <ol><li><a href="classes/Net/SSH/Multi/Channel.html"><span class="parent">Net::SSH::Multi::</span>Channel</a></li><li><a href="classes/Net/SSH/Multi/ChannelProxy.html"><span class="parent">Net::SSH::Multi::</span>ChannelProxy</a></li><li><a href="classes/Net/SSH/Multi/DynamicServer.html"><span class="parent">Net::SSH::Multi::</span>DynamicServer</a></li><li><a href="classes/Net/SSH/Multi/PendingConnection.html"><span class="parent">Net::SSH::Multi::</span>PendingConnection</a></li><li><a href="classes/Net/SSH/Multi/Server.html"><span class="parent">Net::SSH::Multi::</span>Server</a></li><li><a href="classes/Net/SSH/Multi/ServerList.html"><span class="parent">Net::SSH::Multi::</span>ServerList</a></li><li><a href="classes/Net/SSH/Multi/Session.html"><span class="parent">Net::SSH::Multi::</span>Session</a></li><li><a href="classes/Net/SSH/Multi/SessionActions.html"><span class="parent">Net::SSH::Multi::</span>SessionActions</a></li><li><a href="classes/Net/SSH/Multi/Subsession.html"><span class="parent">Net::SSH::Multi::</span>Subsession</a></li><li><a href="classes/Net/SSH/Multi/Version.html"><span class="parent">Net::SSH::Multi::</span>Version</a></li>
+ </ol></li>
+ </ol></li>
+ </ol></li>
+ </ol>
+ </div>
+ </body>
+</html>
diff --git a/fr_file_index.html b/fr_file_index.html
new file mode 100644
index 0000000..2ecd47b
--- /dev/null
+++ b/fr_file_index.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>Files [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <base target='docwin'>
+ </head>
+ <body class='list'>
+ <div id='index'>
+ <h1>Files</h1>
+ <ol class='files' id='index-entries'>
+ <li><a href="files/CHANGELOG_rdoc.html">CHANGELOG.rdoc</a></li>
+ <li><a href="files/README_rdoc.html">README.rdoc</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi_rb.html">lib/net/ssh/multi.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/channel_rb.html">lib/net/ssh/multi/channel.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/channel_proxy_rb.html">lib/net/ssh/multi/channel_proxy.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/dynamic_server_rb.html">lib/net/ssh/multi/dynamic_server.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/pending_connection_rb.html">lib/net/ssh/multi/pending_connection.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/server_rb.html">lib/net/ssh/multi/server.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/server_list_rb.html">lib/net/ssh/multi/server_list.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/session_actions_rb.html">lib/net/ssh/multi/session_actions.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/subsession_rb.html">lib/net/ssh/multi/subsession.rb</a></li>
+ <li class='other'><a href="files/lib/net/ssh/multi/version_rb.html">lib/net/ssh/multi/version.rb</a></li>
+ <li>
+ <a class='show' href='#' onclick='this.parentNode.parentNode.className += " expanded"; this.parentNode.removeChild(this); return false'>show all</a>
+ </li>
+ </ol>
+ </div>
+ </body>
+</html>
diff --git a/fr_method_index.html b/fr_method_index.html
new file mode 100644
index 0000000..9d6f6c9
--- /dev/null
+++ b/fr_method_index.html
@@ -0,0 +1,4567 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang='en'>
+ <head>
+ <title>Methods [Control multiple Net::SSH connections via a single interface.]</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ <link href='rdoc-style.css' media='screen' rel='stylesheet' type='text/css'>
+ <base target='docwin'>
+ </head>
+ <body class='list'>
+ <div id='index'>
+ <h1>Methods</h1>
+ <script type='text/javascript'>
+ /* Prototype JavaScript framework, version 1.6.0.3
+ * (c) 2005-2008 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://www.prototypejs.org/
+ *
+ *--------------------------------------------------------------------------*/
+
+ var Prototype = {
+ Version: '1.6.0.3',
+
+ Browser: {
+ IE: !!(window.attachEvent &&
+ navigator.userAgent.indexOf('Opera') === -1),
+ Opera: navigator.userAgent.indexOf('Opera') > -1,
+ WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
+ Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
+ navigator.userAgent.indexOf('KHTML') === -1,
+ MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
+ },
+
+ BrowserFeatures: {
+ XPath: !!document.evaluate,
+ SelectorsAPI: !!document.querySelector,
+ ElementExtensions: !!window.HTMLElement,
+ SpecificElementExtensions:
+ document.createElement('div')['__proto__'] &&
+ document.createElement('div')['__proto__'] !==
+ document.createElement('form')['__proto__']
+ },
+
+ ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
+ JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
+
+ emptyFunction: function() { },
+ K: function(x) { return x }
+ };
+
+ if (Prototype.Browser.MobileSafari)
+ Prototype.BrowserFeatures.SpecificElementExtensions = false;
+
+
+ /* Based on Alex Arnell's inheritance implementation. */
+ var Class = {
+ create: function() {
+ var parent = null, properties = $A(arguments);
+ if (Object.isFunction(properties[0]))
+ parent = properties.shift();
+
+ function klass() {
+ this.initialize.apply(this, arguments);
+ }
+
+ Object.extend(klass, Class.Methods);
+ klass.superclass = parent;
+ klass.subclasses = [];
+
+ if (parent) {
+ var subclass = function() { };
+ subclass.prototype = parent.prototype;
+ klass.prototype = new subclass;
+ parent.subclasses.push(klass);
+ }
+
+ for (var i = 0; i < properties.length; i++)
+ klass.addMethods(properties[i]);
+
+ if (!klass.prototype.initialize)
+ klass.prototype.initialize = Prototype.emptyFunction;
+
+ klass.prototype.constructor = klass;
+
+ return klass;
+ }
+ };
+
+ Class.Methods = {
+ addMethods: function(source) {
+ var ancestor = this.superclass && this.superclass.prototype;
+ var properties = Object.keys(source);
+
+ if (!Object.keys({ toString: true }).length)
+ properties.push("toString", "valueOf");
+
+ for (var i = 0, length = properties.length; i < length; i++) {
+ var property = properties[i], value = source[property];
+ if (ancestor && Object.isFunction(value) &&
+ value.argumentNames().first() == "$super") {
+ var method = value;
+ value = (function(m) {
+ return function() { return ancestor[m].apply(this, arguments) };
+ })(property).wrap(method);
+
+ value.valueOf = method.valueOf.bind(method);
+ value.toString = method.toString.bind(method);
+ }
+ this.prototype[property] = value;
+ }
+
+ return this;
+ }
+ };
+
+ var Abstract = { };
+
+ Object.extend = function(destination, source) {
+ for (var property in source)
+ destination[property] = source[property];
+ return destination;
+ };
+
+ Object.extend(Object, {
+ inspect: function(object) {
+ try {
+ if (Object.isUndefined(object)) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : String(object);
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ toJSON: function(object) {
+ var type = typeof object;
+ switch (type) {
+ case 'undefined':
+ case 'function':
+ case 'unknown': return;
+ case 'boolean': return object.toString();
+ }
+
+ if (object === null) return 'null';
+ if (object.toJSON) return object.toJSON();
+ if (Object.isElement(object)) return;
+
+ var results = [];
+ for (var property in object) {
+ var value = Object.toJSON(object[property]);
+ if (!Object.isUndefined(value))
+ results.push(property.toJSON() + ': ' + value);
+ }
+
+ return '{' + results.join(', ') + '}';
+ },
+
+ toQueryString: function(object) {
+ return $H(object).toQueryString();
+ },
+
+ toHTML: function(object) {
+ return object && object.toHTML ? object.toHTML() : String.interpret(object);
+ },
+
+ keys: function(object) {
+ var keys = [];
+ for (var property in object)
+ keys.push(property);
+ return keys;
+ },
+
+ values: function(object) {
+ var values = [];
+ for (var property in object)
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function(object) {
+ return Object.extend({ }, object);
+ },
+
+ isElement: function(object) {
+ return !!(object && object.nodeType == 1);
+ },
+
+ isArray: function(object) {
+ return object != null && typeof object == "object" &&
+ 'splice' in object && 'join' in object;
+ },
+
+ isHash: function(object) {
+ return object instanceof Hash;
+ },
+
+ isFunction: function(object) {
+ return typeof object == "function";
+ },
+
+ isString: function(object) {
+ return typeof object == "string";
+ },
+
+ isNumber: function(object) {
+ return typeof object == "number";
+ },
+
+ isUndefined: function(object) {
+ return typeof object == "undefined";
+ }
+ });
+
+ Object.extend(Function.prototype, {
+ argumentNames: function() {
+ var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
+ .replace(/\s+/g, '').split(',');
+ return names.length == 1 && !names[0] ? [] : names;
+ },
+
+ bind: function() {
+ if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+ },
+
+ bindAsEventListener: function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [event || window.event].concat(args));
+ }
+ },
+
+ curry: function() {
+ if (!arguments.length) return this;
+ var __method = this, args = $A(arguments);
+ return function() {
+ return __method.apply(this, args.concat($A(arguments)));
+ }
+ },
+
+ delay: function() {
+ var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+ return window.setTimeout(function() {
+ return __method.apply(__method, args);
+ }, timeout);
+ },
+
+ defer: function() {
+ var args = [0.01].concat($A(arguments));
+ return this.delay.apply(this, args);
+ },
+
+ wrap: function(wrapper) {
+ var __method = this;
+ return function() {
+ return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+ }
+ },
+
+ methodize: function() {
+ if (this._methodized) return this._methodized;
+ var __method = this;
+ return this._methodized = function() {
+ return __method.apply(null, [this].concat($A(arguments)));
+ };
+ }
+ });
+
+ Date.prototype.toJSON = function() {
+ return '"' + this.getUTCFullYear() + '-' +
+ (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
+ this.getUTCDate().toPaddedString(2) + 'T' +
+ this.getUTCHours().toPaddedString(2) + ':' +
+ this.getUTCMinutes().toPaddedString(2) + ':' +
+ this.getUTCSeconds().toPaddedString(2) + 'Z"';
+ };
+
+ var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) { }
+ }
+
+ return returnValue;
+ }
+ };
+
+ RegExp.prototype.match = RegExp.prototype.test;
+
+ RegExp.escape = function(str) {
+ return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ var PeriodicalExecuter = Class.create({
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ execute: function() {
+ this.callback(this);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.execute();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+ });
+ Object.extend(String, {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ },
+ specialChar: {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '\\': '\\\\'
+ }
+ });
+
+ Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = Object.isUndefined(count) ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return String(this);
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = Object.isUndefined(truncation) ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : String(this);
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var self = arguments.callee;
+ self.text.data = this;
+ return self.div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = new Element('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
+ $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
+ div.childNodes[0].nodeValue) : '';
+ },
+
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ return match[1].split(separator || '&').inject({ }, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var key = decodeURIComponent(pair.shift());
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ return hash;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ succ: function() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ },
+
+ times: function(count) {
+ return count < 1 ? '' : new Array(count + 1).join(this);
+ },
+
+ camelize: function() {
+ var parts = this.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+
+ var camelized = this.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++)
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+ return camelized;
+ },
+
+ capitalize: function() {
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ },
+
+ underscore: function() {
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+ },
+
+ dasherize: function() {
+ return this.gsub(/_/,'-');
+ },
+
+ inspect: function(useDoubleQuotes) {
+ var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
+ var character = String.specialChar[match[0]];
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ },
+
+ toJSON: function() {
+ return this.inspect(true);
+ },
+
+ unfilterJSON: function(filter) {
+ return this.sub(filter || Prototype.JSONFilter, '#{1}');
+ },
+
+ isJSON: function() {
+ var str = this;
+ if (str.blank()) return false;
+ str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
+ return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
+ },
+
+ evalJSON: function(sanitize) {
+ var json = this.unfilterJSON();
+ try {
+ if (!sanitize || json.isJSON()) return eval('(' + json + ')');
+ } catch (e) { }
+ throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
+ },
+
+ include: function(pattern) {
+ return this.indexOf(pattern) > -1;
+ },
+
+ startsWith: function(pattern) {
+ return this.indexOf(pattern) === 0;
+ },
+
+ endsWith: function(pattern) {
+ var d = this.length - pattern.length;
+ return d >= 0 && this.lastIndexOf(pattern) === d;
+ },
+
+ empty: function() {
+ return this == '';
+ },
+
+ blank: function() {
+ return /^\s*$/.test(this);
+ },
+
+ interpolate: function(object, pattern) {
+ return new Template(this, pattern).evaluate(object);
+ }
+ });
+
+ if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
+ escapeHTML: function() {
+ return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+ },
+ unescapeHTML: function() {
+ return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
+ }
+ });
+
+ String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (Object.isFunction(replacement)) return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+ };
+
+ String.prototype.parseQuery = String.prototype.toQueryParams;
+
+ Object.extend(String.prototype.escapeHTML, {
+ div: document.createElement('div'),
+ text: document.createTextNode('')
+ });
+
+ String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
+
+ var Template = Class.create({
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ if (Object.isFunction(object.toTemplateReplacements))
+ object = object.toTemplateReplacements();
+
+ return this.template.gsub(this.pattern, function(match) {
+ if (object == null) return '';
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3];
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + String.interpret(ctx);
+ });
+ }
+ });
+ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+
+ var $break = { };
+
+ var Enumerable = {
+ each: function(iterator, context) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ iterator.call(context, value, index++);
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ },
+
+ eachSlice: function(number, iterator, context) {
+ var index = -number, slices = [], array = this.toArray();
+ if (number < 1) return array;
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.collect(iterator, context);
+ },
+
+ all: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!iterator.call(context, value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!iterator.call(context, value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator.call(context, value, index));
+ });
+ return results;
+ },
+
+ detect: function(iterator, context) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator.call(context, value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(filter, iterator, context) {
+ iterator = iterator || Prototype.K;
+ var results = [];
+
+ if (Object.isString(filter))
+ filter = new RegExp(filter);
+
+ this.each(function(value, index) {
+ if (filter.match(value))
+ results.push(iterator.call(context, value, index));
+ });
+ return results;
+ },
+
+ include: function(object) {
+ if (Object.isFunction(this.indexOf))
+ if (this.indexOf(object) != -1) return true;
+
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inGroupsOf: function(number, fillWith) {
+ fillWith = Object.isUndefined(fillWith) ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ },
+
+ inject: function(memo, iterator, context) {
+ this.each(function(value, index) {
+ memo = iterator.call(context, memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index);
+ if (result == null || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var result;
+ this.each(function(value, index) {
+ value = iterator.call(context, value, index);
+ if (result == null || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator, context) {
+ iterator = iterator || Prototype.K;
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ (iterator.call(context, value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator, context) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator.call(context, value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator, context) {
+ return this.map(function(value, index) {
+ return {
+ value: value,
+ criteria: iterator.call(context, value, index)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.map();
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (Object.isFunction(args.last()))
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ size: function() {
+ return this.toArray().length;
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+ };
+
+ Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ filter: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray,
+ every: Enumerable.all,
+ some: Enumerable.any
+ });
+ function $A(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+ }
+
+ if (Prototype.Browser.WebKit) {
+ $A = function(iterable) {
+ if (!iterable) return [];
+ // In Safari, only use the `toArray` method if it's not a NodeList.
+ // A NodeList is a function, has an function `item` property, and a numeric
+ // `length` property. Adapted from Google Doctype.
+ if (!(typeof iterable === 'function' && typeof iterable.length ===
+ 'number' && typeof iterable.item === 'function') && iterable.toArray)
+ return iterable.toArray();
+ var length = iterable.length || 0, results = new Array(length);
+ while (length--) results[length] = iterable[length];
+ return results;
+ };
+ }
+
+ Array.from = $A;
+
+ Object.extend(Array.prototype, Enumerable);
+
+ if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+
+ Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0, length = this.length; i < length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(Object.isArray(value) ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function(sorted) {
+ return this.inject([], function(array, value, index) {
+ if (0 == index || (sorted ? array.last() != value : !array.include(value)))
+ array.push(value);
+ return array;
+ });
+ },
+
+ intersect: function(array) {
+ return this.uniq().findAll(function(item) {
+ return array.detect(function(value) { return item === value });
+ });
+ },
+
+ clone: function() {
+ return [].concat(this);
+ },
+
+ size: function() {
+ return this.length;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ },
+
+ toJSON: function() {
+ var results = [];
+ this.each(function(object) {
+ var value = Object.toJSON(object);
+ if (!Object.isUndefined(value)) results.push(value);
+ });
+ return '[' + results.join(', ') + ']';
+ }
+ });
+
+ // use native browser JS 1.6 implementation if available
+ if (Object.isFunction(Array.prototype.forEach))
+ Array.prototype._each = Array.prototype.forEach;
+
+ if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
+ i || (i = 0);
+ var length = this.length;
+ if (i < 0) i = length + i;
+ for (; i < length; i++)
+ if (this[i] === item) return i;
+ return -1;
+ };
+
+ if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
+ i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
+ var n = this.slice(0, i).reverse().indexOf(item);
+ return (n < 0) ? n : i - n - 1;
+ };
+
+ Array.prototype.toArray = Array.prototype.clone;
+
+ function $w(string) {
+ if (!Object.isString(string)) return [];
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+ }
+
+ if (Prototype.Browser.Opera){
+ Array.prototype.concat = function() {
+ var array = [];
+ for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ if (Object.isArray(arguments[i])) {
+ for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+ array.push(arguments[i][j]);
+ } else {
+ array.push(arguments[i]);
+ }
+ }
+ return array;
+ };
+ }
+ Object.extend(Number.prototype, {
+ toColorPart: function() {
+ return this.toPaddedString(2, 16);
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator, context) {
+ $R(0, this, true).each(iterator, context);
+ return this;
+ },
+
+ toPaddedString: function(length, radix) {
+ var string = this.toString(radix || 10);
+ return '0'.times(length - string.length) + string;
+ },
+
+ toJSON: function() {
+ return isFinite(this) ? this.toString() : 'null';
+ }
+ });
+
+ $w('abs round ceil floor').each(function(method){
+ Number.prototype[method] = Math[method].methodize();
+ });
+ function $H(object) {
+ return new Hash(object);
+ };
+
+ var Hash = Class.create(Enumerable, (function() {
+
+ function toQueryPair(key, value) {
+ if (Object.isUndefined(value)) return key;
+ return key + '=' + encodeURIComponent(String.interpret(value));
+ }
+
+ return {
+ initialize: function(object) {
+ this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+ },
+
+ _each: function(iterator) {
+ for (var key in this._object) {
+ var value = this._object[key], pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ set: function(key, value) {
+ return this._object[key] = value;
+ },
+
+ get: function(key) {
+ // simulating poorly supported hasOwnProperty
+ if (this._object[key] !== Object.prototype[key])
+ return this._object[key];
+ },
+
+ unset: function(key) {
+ var value = this._object[key];
+ delete this._object[key];
+ return value;
+ },
+
+ toObject: function() {
+ return Object.clone(this._object);
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ index: function(value) {
+ var match = this.detect(function(pair) {
+ return pair.value === value;
+ });
+ return match && match.key;
+ },
+
+ merge: function(object) {
+ return this.clone().update(object);
+ },
+
+ update: function(object) {
+ return new Hash(object).inject(this, function(result, pair) {
+ result.set(pair.key, pair.value);
+ return result;
+ });
+ },
+
+ toQueryString: function() {
+ return this.inject([], function(results, pair) {
+ var key = encodeURIComponent(pair.key), values = pair.value;
+
+ if (values && typeof values == 'object') {
+ if (Object.isArray(values))
+ return results.concat(values.map(toQueryPair.curry(key)));
+ } else results.push(toQueryPair(key, values));
+ return results;
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ },
+
+ toJSON: function() {
+ return Object.toJSON(this.toObject());
+ },
+
+ clone: function() {
+ return new Hash(this);
+ }
+ }
+ })());
+
+ Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
+ Hash.from = $H;
+ var ObjectRange = Class.create(Enumerable, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+ });
+
+ var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+ };
+
+ var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+ };
+
+ Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (Object.isFunction(responder[callback])) {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) { }
+ }
+ });
+ }
+ };
+
+ Object.extend(Ajax.Responders, Enumerable);
+
+ Ajax.Responders.register({
+ onCreate: function() { Ajax.activeRequestCount++ },
+ onComplete: function() { Ajax.activeRequestCount-- }
+ });
+
+ Ajax.Base = Class.create({
+ initialize: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: '',
+ evalJSON: true,
+ evalJS: true
+ };
+ Object.extend(this.options, options || { });
+
+ this.options.method = this.options.method.toLowerCase();
+
+ if (Object.isString(this.options.parameters))
+ this.options.parameters = this.options.parameters.toQueryParams();
+ else if (Object.isHash(this.options.parameters))
+ this.options.parameters = this.options.parameters.toObject();
+ }
+ });
+
+ Ajax.Request = Class.create(Ajax.Base, {
+ _complete: false,
+
+ initialize: function($super, url, options) {
+ $super(options);
+ this.transport = Ajax.getTransport();
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = Object.clone(this.options.parameters);
+
+ if (!['get', 'post'].include(this.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ this.parameters = params;
+
+ if (params = Object.toQueryString(params)) {
+ // when GET, append parameters to URL
+ if (this.method == 'get')
+ this.url += (this.url.include('?') ? '&' : '?') + params;
+ else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ params += '&_=';
+ }
+
+ try {
+ var response = new Ajax.Response(this);
+ if (this.options.onCreate) this.options.onCreate(response);
+ Ajax.Responders.dispatch('onCreate', this, response);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ this.body = this.method == 'post' ? (this.options.postBody || params) : null;
+ this.transport.send(this.body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (Object.isFunction(extras.push))
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ var status = this.getStatus();
+ return !status || (status >= 200 && status < 300);
+ },
+
+ getStatus: function() {
+ try {
+ return this.transport.status || 0;
+ } catch (e) { return 0 }
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + response.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ var contentType = response.getHeader('Content-type');
+ if (this.options.evalJS == 'force'
+ || (this.options.evalJS && this.isSameOrigin() && contentType
+ && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
+ Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ isSameOrigin: function() {
+ var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
+ return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
+ protocol: location.protocol,
+ domain: document.domain,
+ port: location.port ? ':' + location.port : ''
+ }));
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name) || null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval((this.transport.responseText || '').unfilterJSON());
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+ });
+
+ Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+ Ajax.Response = Class.create({
+ initialize: function(request){
+ this.request = request;
+ var transport = this.transport = request.transport,
+ readyState = this.readyState = transport.readyState;
+
+ if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
+ this.status = this.getStatus();
+ this.statusText = this.getStatusText();
+ this.responseText = String.interpret(transport.responseText);
+ this.headerJSON = this._getHeaderJSON();
+ }
+
+ if(readyState == 4) {
+ var xml = transport.responseXML;
+ this.responseXML = Object.isUndefined(xml) ? null : xml;
+ this.responseJSON = this._getResponseJSON();
+ }
+ },
+
+ status: 0,
+ statusText: '',
+
+ getStatus: Ajax.Request.prototype.getStatus,
+
+ getStatusText: function() {
+ try {
+ return this.transport.statusText || '';
+ } catch (e) { return '' }
+ },
+
+ getHeader: Ajax.Request.prototype.getHeader,
+
+ getAllHeaders: function() {
+ try {
+ return this.getAllResponseHeaders();
+ } catch (e) { return null }
+ },
+
+ getResponseHeader: function(name) {
+ return this.transport.getResponseHeader(name);
+ },
+
+ getAllResponseHeaders: function() {
+ return this.transport.getAllResponseHeaders();
+ },
+
+ _getHeaderJSON: function() {
+ var json = this.getHeader('X-JSON');
+ if (!json) return null;
+ json = decodeURIComponent(escape(json));
+ try {
+ return json.evalJSON(this.request.options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ },
+
+ _getResponseJSON: function() {
+ var options = this.request.options;
+ if (!options.evalJSON || (options.evalJSON != 'force' &&
+ !(this.getHeader('Content-type') || '').include('application/json')) ||
+ this.responseText.blank())
+ return null;
+ try {
+ return this.responseText.evalJSON(options.sanitizeJSON ||
+ !this.request.isSameOrigin());
+ } catch (e) {
+ this.request.dispatchException(e);
+ }
+ }
+ });
+
+ Ajax.Updater = Class.create(Ajax.Request, {
+ initialize: function($super, container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ };
+
+ options = Object.clone(options);
+ var onComplete = options.onComplete;
+ options.onComplete = (function(response, json) {
+ this.updateContent(response.responseText);
+ if (Object.isFunction(onComplete)) onComplete(response, json);
+ }).bind(this);
+
+ $super(url, options);
+ },
+
+ updateContent: function(responseText) {
+ var receiver = this.container[this.success() ? 'success' : 'failure'],
+ options = this.options;
+
+ if (!options.evalScripts) responseText = responseText.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (options.insertion) {
+ if (Object.isString(options.insertion)) {
+ var insertion = { }; insertion[options.insertion] = responseText;
+ receiver.insert(insertion);
+ }
+ else options.insertion(receiver, responseText);
+ }
+ else receiver.update(responseText);
+ }
+ }
+ });
+
+ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
+ initialize: function($super, container, url, options) {
+ $super(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = { };
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(response) {
+ if (this.options.decay) {
+ this.decay = (response.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = response.responseText;
+ }
+ this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+ });
+ function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+ if (Object.isString(element))
+ element = document.getElementById(element);
+ return Element.extend(element);
+ }
+
+ if (Prototype.BrowserFeatures.XPath) {
+ document._getElementsByXPath = function(expression, parentElement) {
+ var results = [];
+ var query = document.evaluate(expression, $(parentElement) || document,
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
+ results.push(Element.extend(query.snapshotItem(i)));
+ return results;
+ };
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ if (!window.Node) var Node = { };
+
+ if (!Node.ELEMENT_NODE) {
+ // DOM level 2 ECMAScript Language Binding
+ Object.extend(Node, {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+ });
+ }
+
+ (function() {
+ var element = this.Element;
+ this.Element = function(tagName, attributes) {
+ attributes = attributes || { };
+ tagName = tagName.toLowerCase();
+ var cache = Element.cache;
+ if (Prototype.Browser.IE && attributes.name) {
+ tagName = '<' + tagName + ' name="' + attributes.name + '">';
+ delete attributes.name;
+ return Element.writeAttribute(document.createElement(tagName), attributes);
+ }
+ if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
+ return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
+ };
+ Object.extend(this.Element, element || { });
+ if (element) this.Element.prototype = element.prototype;
+ }).call(window);
+
+ Element.cache = { };
+
+ Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function(element) {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+ hide: function(element) {
+ element = $(element);
+ element.style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ element = $(element);
+ element.style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+ content = Object.toHTML(content);
+ element.innerHTML = content.stripScripts();
+ content.evalScripts.bind(content).defer();
+ return element;
+ },
+
+ replace: function(element, content) {
+ element = $(element);
+ if (content && content.toElement) content = content.toElement();
+ else if (!Object.isElement(content)) {
+ content = Object.toHTML(content);
+ var range = element.ownerDocument.createRange();
+ range.selectNode(element);
+ content.evalScripts.bind(content).defer();
+ content = range.createContextualFragment(content.stripScripts());
+ }
+ element.parentNode.replaceChild(content, element);
+ return element;
+ },
+
+ insert: function(element, insertions) {
+ element = $(element);
+
+ if (Object.isString(insertions) || Object.isNumber(insertions) ||
+ Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
+ insertions = {bottom:insertions};
+
+ var content, insert, tagName, childNodes;
+
+ for (var position in insertions) {
+ content = insertions[position];
+ position = position.toLowerCase();
+ insert = Element._insertionTranslations[position];
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ insert(element, content);
+ continue;
+ }
+
+ content = Object.toHTML(content);
+
+ tagName = ((position == 'before' || position == 'after')
+ ? element.parentNode : element).tagName.toUpperCase();
+
+ childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+
+ if (position == 'top' || position == 'after') childNodes.reverse();
+ childNodes.each(insert.curry(element));
+
+ content.evalScripts.bind(content).defer();
+ }
+
+ return element;
+ },
+
+ wrap: function(element, wrapper, attributes) {
+ element = $(element);
+ if (Object.isElement(wrapper))
+ $(wrapper).writeAttribute(attributes || { });
+ else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
+ else wrapper = new Element('div', wrapper);
+ if (element.parentNode)
+ element.parentNode.replaceChild(wrapper, element);
+ wrapper.appendChild(element);
+ return wrapper;
+ },
+
+ inspect: function(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function(element) {
+ return $(element).select("*");
+ },
+
+ firstDescendant: function(element) {
+ element = $(element).firstChild;
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ return $(element);
+ },
+
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
+ previousSiblings: function(element) {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function(element, selector) {
+ if (Object.isString(selector))
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(element.parentNode);
+ var ancestors = element.ancestors();
+ return Object.isNumber(expression) ? ancestors[expression] :
+ Selector.findElement(ancestors, expression, index);
+ },
+
+ down: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return element.firstDescendant();
+ return Object.isNumber(expression) ? element.descendants()[expression] :
+ Element.select(element, expression)[index || 0];
+ },
+
+ previous: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
+ var previousSiblings = element.previousSiblings();
+ return Object.isNumber(expression) ? previousSiblings[expression] :
+ Selector.findElement(previousSiblings, expression, index);
+ },
+
+ next: function(element, expression, index) {
+ element = $(element);
+ if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
+ var nextSiblings = element.nextSiblings();
+ return Object.isNumber(expression) ? nextSiblings[expression] :
+ Selector.findElement(nextSiblings, expression, index);
+ },
+
+ select: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ adjacent: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element.parentNode, args).without(element);
+ },
+
+ identify: function(element) {
+ element = $(element);
+ var id = element.readAttribute('id'), self = arguments.callee;
+ if (id) return id;
+ do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+ element.writeAttribute('id', id);
+ return id;
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (Prototype.Browser.IE) {
+ var t = Element._attributeTranslations.read;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ if (name.include(':')) {
+ return (!element.attributes || !element.attributes[name]) ? null :
+ element.attributes[name].value;
+ }
+ }
+ return element.getAttribute(name);
+ },
+
+ writeAttribute: function(element, name, value) {
+ element = $(element);
+ var attributes = { }, t = Element._attributeTranslations.write;
+
+ if (typeof name == 'object') attributes = name;
+ else attributes[name] = Object.isUndefined(value) ? true : value;
+
+ for (var attr in attributes) {
+ name = t.names[attr] || attr;
+ value = attributes[attr];
+ if (t.values[attr]) name = t.values[attr](element, value);
+ if (value === false || value === null)
+ element.removeAttribute(name);
+ else if (value === true)
+ element.setAttribute(name, name);
+ else element.setAttribute(name, value);
+ }
+ return element;
+ },
+
+ getHeight: function(element) {
+ return $(element).getDimensions().height;
+ },
+
+ getWidth: function(element) {
+ return $(element).getDimensions().width;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ var elementClassName = element.className;
+ return (elementClassName.length > 0 && (elementClassName == className ||
+ new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ if (!element.hasClassName(className))
+ element.className += (element.className ? ' ' : '') + className;
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ element.className = element.className.replace(
+ new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return element[element.hasClassName(className) ?
+ 'removeClassName' : 'addClassName'](className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ var node = element.firstChild;
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.blank();
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+
+ if (element.compareDocumentPosition)
+ return (element.compareDocumentPosition(ancestor) & 8) === 8;
+
+ if (ancestor.contains)
+ return ancestor.contains(element) && ancestor !== element;
+
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = element.cumulativeOffset();
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ style = style == 'float' ? 'cssFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value || value == 'auto') {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ }
+ if (style == 'opacity') return value ? parseFloat(value) : 1.0;
+ return value == 'auto' ? null : value;
+ },
+
+ getOpacity: function(element) {
+ return $(element).getStyle('opacity');
+ },
+
+ setStyle: function(element, styles) {
+ element = $(element);
+ var elementStyle = element.style, match;
+ if (Object.isString(styles)) {
+ element.style.cssText += ';' + styles;
+ return styles.include('opacity') ?
+ element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
+ }
+ for (var property in styles)
+ if (property == 'opacity') element.setOpacity(styles[property]);
+ else
+ elementStyle[(property == 'float' || property == 'cssFloat') ?
+ (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
+ property] = styles[property];
+
+ return element;
+ },
+
+ setOpacity: function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ var display = element.getStyle('display');
+ if (display != 'none' && display != null) // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (Prototype.Browser.Opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return element;
+ element._overflow = Element.getStyle(element, 'overflow') || 'auto';
+ if (element._overflow !== 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return element;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if (element.tagName.toUpperCase() == 'BODY') break;
+ var p = Element.getStyle(element, 'position');
+ if (p !== 'static') break;
+ }
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'absolute') return element;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ var offsets = element.positionedOffset();
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ return element;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.getStyle('position') == 'relative') return element;
+ // Position.prepare(); // To be done manually by Scripty when it needs it.
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ return element;
+ },
+
+ cumulativeScrollOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ getOffsetParent: function(element) {
+ if (element.offsetParent) return $(element.offsetParent);
+ if (element == document.body) return $(element);
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return $(element);
+
+ return $(document.body);
+ },
+
+ viewportOffset: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent == document.body &&
+ Element.getStyle(element, 'position') == 'absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return Element._returnOffset(valueL, valueT);
+ },
+
+ clonePosition: function(element, source) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || { });
+
+ // find page position of source
+ source = $(source);
+ var p = source.viewportOffset();
+
+ // find coordinate system to use
+ element = $(element);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(element, 'position') == 'absolute') {
+ parent = element.getOffsetParent();
+ delta = parent.viewportOffset();
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if (options.setWidth) element.style.width = source.offsetWidth + 'px';
+ if (options.setHeight) element.style.height = source.offsetHeight + 'px';
+ return element;
+ }
+ };
+
+ Element.Methods.identify.counter = 1;
+
+ Object.extend(Element.Methods, {
+ getElementsBySelector: Element.Methods.select,
+ childElements: Element.Methods.immediateDescendants
+ });
+
+ Element._attributeTranslations = {
+ write: {
+ names: {
+ className: 'class',
+ htmlFor: 'for'
+ },
+ values: { }
+ }
+ };
+
+ if (Prototype.Browser.Opera) {
+ Element.Methods.getStyle = Element.Methods.getStyle.wrap(
+ function(proceed, element, style) {
+ switch (style) {
+ case 'left': case 'top': case 'right': case 'bottom':
+ if (proceed(element, 'position') === 'static') return null;
+ case 'height': case 'width':
+ // returns '0px' for hidden elements; we want it to return null
+ if (!Element.visible(element)) return null;
+
+ // returns the border-box dimensions rather than the content-box
+ // dimensions, so we subtract padding and borders from the value
+ var dim = parseInt(proceed(element, style), 10);
+
+ if (dim !== element['offset' + style.capitalize()])
+ return dim + 'px';
+
+ var properties;
+ if (style === 'height') {
+ properties = ['border-top-width', 'padding-top',
+ 'padding-bottom', 'border-bottom-width'];
+ }
+ else {
+ properties = ['border-left-width', 'padding-left',
+ 'padding-right', 'border-right-width'];
+ }
+ return properties.inject(dim, function(memo, property) {
+ var val = proceed(element, property);
+ return val === null ? memo : memo - parseInt(val, 10);
+ }) + 'px';
+ default: return proceed(element, style);
+ }
+ }
+ );
+
+ Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
+ function(proceed, element, attribute) {
+ if (attribute === 'title') return element.title;
+ return proceed(element, attribute);
+ }
+ );
+ }
+
+ else if (Prototype.Browser.IE) {
+ // IE doesn't report offsets correctly for static elements, so we change them
+ // to "relative" to get the values, then change them back.
+ Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
+ function(proceed, element) {
+ element = $(element);
+ // IE throws an error if element is not in document
+ try { element.offsetParent }
+ catch(e) { return $(document.body) }
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+
+ $w('positionedOffset viewportOffset').each(function(method) {
+ Element.Methods[method] = Element.Methods[method].wrap(
+ function(proceed, element) {
+ element = $(element);
+ try { element.offsetParent }
+ catch(e) { return Element._returnOffset(0,0) }
+ var position = element.getStyle('position');
+ if (position !== 'static') return proceed(element);
+ // Trigger hasLayout on the offset parent so that IE6 reports
+ // accurate offsetTop and offsetLeft values for position: fixed.
+ var offsetParent = element.getOffsetParent();
+ if (offsetParent && offsetParent.getStyle('position') === 'fixed')
+ offsetParent.setStyle({ zoom: 1 });
+ element.setStyle({ position: 'relative' });
+ var value = proceed(element);
+ element.setStyle({ position: position });
+ return value;
+ }
+ );
+ });
+
+ Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
+ function(proceed, element) {
+ try { element.offsetParent }
+ catch(e) { return Element._returnOffset(0,0) }
+ return proceed(element);
+ }
+ );
+
+ Element.Methods.getStyle = function(element, style) {
+ element = $(element);
+ style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
+ var value = element.style[style];
+ if (!value && element.currentStyle) value = element.currentStyle[style];
+
+ if (style == 'opacity') {
+ if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if (value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+
+ if (value == 'auto') {
+ if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
+ return element['offset' + style.capitalize()] + 'px';
+ return null;
+ }
+ return value;
+ };
+
+ Element.Methods.setOpacity = function(element, value) {
+ function stripAlpha(filter){
+ return filter.replace(/alpha\([^\)]*\)/gi,'');
+ }
+ element = $(element);
+ var currentStyle = element.currentStyle;
+ if ((currentStyle && !currentStyle.hasLayout) ||
+ (!currentStyle && element.style.zoom == 'normal'))
+ element.style.zoom = 1;
+
+ var filter = element.getStyle('filter'), style = element.style;
+ if (value == 1 || value === '') {
+ (filter = stripAlpha(filter)) ?
+ style.filter = filter : style.removeAttribute('filter');
+ return element;
+ } else if (value < 0.00001) value = 0;
+ style.filter = stripAlpha(filter) +
+ 'alpha(opacity=' + (value * 100) + ')';
+ return element;
+ };
+
+ Element._attributeTranslations = {
+ read: {
+ names: {
+ 'class': 'className',
+ 'for': 'htmlFor'
+ },
+ values: {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+ _getAttrNode: function(element, attribute) {
+ var node = element.getAttributeNode(attribute);
+ return node ? node.value : "";
+ },
+ _getEv: function(element, attribute) {
+ attribute = element.getAttribute(attribute);
+ return attribute ? attribute.toString().slice(23, -2) : null;
+ },
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+ title: function(element) {
+ return element.title;
+ }
+ }
+ }
+ };
+
+ Element._attributeTranslations.write = {
+ names: Object.extend({
+ cellpadding: 'cellPadding',
+ cellspacing: 'cellSpacing'
+ }, Element._attributeTranslations.read.names),
+ values: {
+ checked: function(element, value) {
+ element.checked = !!value;
+ },
+
+ style: function(element, value) {
+ element.style.cssText = value ? value : '';
+ }
+ }
+ };
+
+ Element._attributeTranslations.has = {};
+
+ $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
+ 'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
+ Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
+ Element._attributeTranslations.has[attr.toLowerCase()] = attr;
+ });
+
+ (function(v) {
+ Object.extend(v, {
+ href: v._getAttr,
+ src: v._getAttr,
+ type: v._getAttr,
+ action: v._getAttrNode,
+ disabled: v._flag,
+ checked: v._flag,
+ readonly: v._flag,
+ multiple: v._flag,
+ onload: v._getEv,
+ onunload: v._getEv,
+ onclick: v._getEv,
+ ondblclick: v._getEv,
+ onmousedown: v._getEv,
+ onmouseup: v._getEv,
+ onmouseover: v._getEv,
+ onmousemove: v._getEv,
+ onmouseout: v._getEv,
+ onfocus: v._getEv,
+ onblur: v._getEv,
+ onkeypress: v._getEv,
+ onkeydown: v._getEv,
+ onkeyup: v._getEv,
+ onsubmit: v._getEv,
+ onreset: v._getEv,
+ onselect: v._getEv,
+ onchange: v._getEv
+ });
+ })(Element._attributeTranslations.read.values);
+ }
+
+ else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1) ? 0.999999 :
+ (value === '') ? '' : (value < 0.00001) ? 0 : value;
+ return element;
+ };
+ }
+
+ else if (Prototype.Browser.WebKit) {
+ Element.Methods.setOpacity = function(element, value) {
+ element = $(element);
+ element.style.opacity = (value == 1 || value === '') ? '' :
+ (value < 0.00001) ? 0 : value;
+
+ if (value == 1)
+ if(element.tagName.toUpperCase() == 'IMG' && element.width) {
+ element.width++; element.width--;
+ } else try {
+ var n = document.createTextNode(' ');
+ element.appendChild(n);
+ element.removeChild(n);
+ } catch (e) { }
+
+ return element;
+ };
+
+ // Safari returns margins on body which is incorrect if the child is absolutely
+ // positioned. For performance reasons, redefine Element#cumulativeOffset for
+ // KHTML/WebKit only.
+ Element.Methods.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return Element._returnOffset(valueL, valueT);
+ };
+ }
+
+ if (Prototype.Browser.IE || Prototype.Browser.Opera) {
+ // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
+ Element.Methods.update = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) return element.update().insert(content);
+
+ content = Object.toHTML(content);
+ var tagName = element.tagName.toUpperCase();
+
+ if (tagName in Element._insertionTranslations.tags) {
+ $A(element.childNodes).each(function(node) { element.removeChild(node) });
+ Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+ .each(function(node) { element.appendChild(node) });
+ }
+ else element.innerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+ }
+
+ if ('outerHTML' in document.createElement('div')) {
+ Element.Methods.replace = function(element, content) {
+ element = $(element);
+
+ if (content && content.toElement) content = content.toElement();
+ if (Object.isElement(content)) {
+ element.parentNode.replaceChild(content, element);
+ return element;
+ }
+
+ content = Object.toHTML(content);
+ var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
+
+ if (Element._insertionTranslations.tags[tagName]) {
+ var nextSibling = element.next();
+ var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
+ parent.removeChild(element);
+ if (nextSibling)
+ fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
+ else
+ fragments.each(function(node) { parent.appendChild(node) });
+ }
+ else element.outerHTML = content.stripScripts();
+
+ content.evalScripts.bind(content).defer();
+ return element;
+ };
+ }
+
+ Element._returnOffset = function(l, t) {
+ var result = [l, t];
+ result.left = l;
+ result.top = t;
+ return result;
+ };
+
+ Element._getContentFromAnonymousElement = function(tagName, html) {
+ var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
+ if (t) {
+ div.innerHTML = t[0] + html + t[1];
+ t[2].times(function() { div = div.firstChild });
+ } else div.innerHTML = html;
+ return $A(div.childNodes);
+ };
+
+ Element._insertionTranslations = {
+ before: function(element, node) {
+ element.parentNode.insertBefore(node, element);
+ },
+ top: function(element, node) {
+ element.insertBefore(node, element.firstChild);
+ },
+ bottom: function(element, node) {
+ element.appendChild(node);
+ },
+ after: function(element, node) {
+ element.parentNode.insertBefore(node, element.nextSibling);
+ },
+ tags: {
+ TABLE: ['<table>', '</table>', 1],
+ TBODY: ['<table><tbody>', '</tbody></table>', 2],
+ TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3],
+ TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
+ SELECT: ['<select>', '</select>', 1]
+ }
+ };
+
+ (function() {
+ Object.extend(this.tags, {
+ THEAD: this.tags.TBODY,
+ TFOOT: this.tags.TBODY,
+ TH: this.tags.TD
+ });
+ }).call(Element._insertionTranslations);
+
+ Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ attribute = Element._attributeTranslations.has[attribute] || attribute;
+ var node = $(element).getAttributeNode(attribute);
+ return !!(node && node.specified);
+ }
+ };
+
+ Element.Methods.ByTag = { };
+
+ Object.extend(Element, Element.Methods);
+
+ if (!Prototype.BrowserFeatures.ElementExtensions &&
+ document.createElement('div')['__proto__']) {
+ window.HTMLElement = { };
+ window.HTMLElement.prototype = document.createElement('div')['__proto__'];
+ Prototype.BrowserFeatures.ElementExtensions = true;
+ }
+
+ Element.extend = (function() {
+ if (Prototype.BrowserFeatures.SpecificElementExtensions)
+ return Prototype.K;
+
+ var Methods = { }, ByTag = Element.Methods.ByTag;
+
+ var extend = Object.extend(function(element) {
+ if (!element || element._extendedByPrototype ||
+ element.nodeType != 1 || element == window) return element;
+
+ var methods = Object.clone(Methods),
+ tagName = element.tagName.toUpperCase(), property, value;
+
+ // extend methods for specific tags
+ if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
+
+ for (property in methods) {
+ value = methods[property];
+ if (Object.isFunction(value) && !(property in element))
+ element[property] = value.methodize();
+ }
+
+ element._extendedByPrototype = Prototype.emptyFunction;
+ return element;
+
+ }, {
+ refresh: function() {
+ // extend methods for all tags (Safari doesn't need this)
+ if (!Prototype.BrowserFeatures.ElementExtensions) {
+ Object.extend(Methods, Element.Methods);
+ Object.extend(Methods, Element.Methods.Simulated);
+ }
+ }
+ });
+
+ extend.refresh();
+ return extend;
+ })();
+
+ Element.hasAttribute = function(element, attribute) {
+ if (element.hasAttribute) return element.hasAttribute(attribute);
+ return Element.Methods.Simulated.hasAttribute(element, attribute);
+ };
+
+ Element.addMethods = function(methods) {
+ var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
+
+ if (!methods) {
+ Object.extend(Form, Form.Methods);
+ Object.extend(Form.Element, Form.Element.Methods);
+ Object.extend(Element.Methods.ByTag, {
+ "FORM": Object.clone(Form.Methods),
+ "INPUT": Object.clone(Form.Element.Methods),
+ "SELECT": Object.clone(Form.Element.Methods),
+ "TEXTAREA": Object.clone(Form.Element.Methods)
+ });
+ }
+
+ if (arguments.length == 2) {
+ var tagName = methods;
+ methods = arguments[1];
+ }
+
+ if (!tagName) Object.extend(Element.Methods, methods || { });
+ else {
+ if (Object.isArray(tagName)) tagName.each(extend);
+ else extend(tagName);
+ }
+
+ function extend(tagName) {
+ tagName = tagName.toUpperCase();
+ if (!Element.Methods.ByTag[tagName])
+ Element.Methods.ByTag[tagName] = { };
+ Object.extend(Element.Methods.ByTag[tagName], methods);
+ }
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!Object.isFunction(value)) continue;
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = value.methodize();
+ }
+ }
+
+ function findDOMClass(tagName) {
+ var klass;
+ var trans = {
+ "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
+ "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
+ "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
+ "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
+ "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
+ "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
+ "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
+ "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
+ "FrameSet", "IFRAME": "IFrame"
+ };
+ if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName + 'Element';
+ if (window[klass]) return window[klass];
+ klass = 'HTML' + tagName.capitalize() + 'Element';
+ if (window[klass]) return window[klass];
+
+ window[klass] = { };
+ window[klass].prototype = document.createElement(tagName)['__proto__'];
+ return window[klass];
+ }
+
+ if (F.ElementExtensions) {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+ }
+
+ if (F.SpecificElementExtensions) {
+ for (var tag in Element.Methods.ByTag) {
+ var klass = findDOMClass(tag);
+ if (Object.isUndefined(klass)) continue;
+ copy(T[tag], klass.prototype);
+ }
+ }
+
+ Object.extend(Element, Element.Methods);
+ delete Element.ByTag;
+
+ if (Element.extend.refresh) Element.extend.refresh();
+ Element.cache = { };
+ };
+
+ document.viewport = {
+ getDimensions: function() {
+ var dimensions = { }, B = Prototype.Browser;
+ $w('width height').each(function(d) {
+ var D = d.capitalize();
+ if (B.WebKit && !document.evaluate) {
+ // Safari <3.0 needs self.innerWidth/Height
+ dimensions[d] = self['inner' + D];
+ } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
+ // Opera <9.5 needs document.body.clientWidth/Height
+ dimensions[d] = document.body['client' + D]
+ } else {
+ dimensions[d] = document.documentElement['client' + D];
+ }
+ });
+ return dimensions;
+ },
+
+ getWidth: function() {
+ return this.getDimensions().width;
+ },
+
+ getHeight: function() {
+ return this.getDimensions().height;
+ },
+
+ getScrollOffsets: function() {
+ return Element._returnOffset(
+ window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
+ window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+ }
+ };
+ /* Portions of the Selector class are derived from Jack Slocum's DomQuery,
+ * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
+ * license. Please see http://www.yui-ext.com/ for more information. */
+
+ var Selector = Class.create({
+ initialize: function(expression) {
+ this.expression = expression.strip();
+
+ if (this.shouldUseSelectorsAPI()) {
+ this.mode = 'selectorsAPI';
+ } else if (this.shouldUseXPath()) {
+ this.mode = 'xpath';
+ this.compileXPathMatcher();
+ } else {
+ this.mode = "normal";
+ this.compileMatcher();
+ }
+
+ },
+
+ shouldUseXPath: function() {
+ if (!Prototype.BrowserFeatures.XPath) return false;
+
+ var e = this.expression;
+
+ // Safari 3 chokes on :*-of-type and :empty
+ if (Prototype.Browser.WebKit &&
+ (e.include("-of-type") || e.include(":empty")))
+ return false;
+
+ // XPath can't do namespaced attributes, nor can it read
+ // the "checked" property from DOM nodes
+ if ((/(\[[\w-]*?:|:checked)/).test(e))
+ return false;
+
+ return true;
+ },
+
+ shouldUseSelectorsAPI: function() {
+ if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+
+ if (!Selector._div) Selector._div = new Element('div');
+
+ // Make sure the browser treats the selector as valid. Test on an
+ // isolated element to minimize cost of this check.
+ try {
+ Selector._div.querySelector(this.expression);
+ } catch(e) {
+ return false;
+ }
+
+ return true;
+ },
+
+ compileMatcher: function() {
+ var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
+ c = Selector.criteria, le, p, m;
+
+ if (Selector._cache[e]) {
+ this.matcher = Selector._cache[e];
+ return;
+ }
+
+ this.matcher = ["this.matcher = function(root) {",
+ "var r = root, h = Selector.handlers, c = false, n;"];
+
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
+ new Template(c[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.matcher.push("return h.unique(n);\n}");
+ eval(this.matcher.join('\n'));
+ Selector._cache[this.expression] = this.matcher;
+ },
+
+ compileXPathMatcher: function() {
+ var e = this.expression, ps = Selector.patterns,
+ x = Selector.xpath, le, m;
+
+ if (Selector._cache[e]) {
+ this.xpath = Selector._cache[e]; return;
+ }
+
+ this.matcher = ['.//*'];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ if (m = e.match(ps[i])) {
+ this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
+ new Template(x[i]).evaluate(m));
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+
+ this.xpath = this.matcher.join('');
+ Selector._cache[this.expression] = this.xpath;
+ },
+
+ findElements: function(root) {
+ root = root || document;
+ var e = this.expression, results;
+
+ switch (this.mode) {
+ case 'selectorsAPI':
+ // querySelectorAll queries document-wide, then filters to descendants
+ // of the context element. That's not what we want.
+ // Add an explicit context to the selector if necessary.
+ if (root !== document) {
+ var oldId = root.id, id = $(root).identify();
+ e = "#" + id + " " + e;
+ }
+
+ results = $A(root.querySelectorAll(e)).map(Element.extend);
+ root.id = oldId;
+
+ return results;
+ case 'xpath':
+ return document._getElementsByXPath(this.xpath, root);
+ default:
+ return this.matcher(root);
+ }
+ },
+
+ match: function(element) {
+ this.tokens = [];
+
+ var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
+ var le, p, m;
+
+ while (e && le !== e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ // use the Selector.assertions methods unless the selector
+ // is too complex.
+ if (as[i]) {
+ this.tokens.push([i, Object.clone(m)]);
+ e = e.replace(m[0], '');
+ } else {
+ // reluctantly do a document-wide search
+ // and look for a match in the array
+ return this.findElements(document).include(element);
+ }
+ }
+ }
+ }
+
+ var match = true, name, matches;
+ for (var i = 0, token; token = this.tokens[i]; i++) {
+ name = token[0], matches = token[1];
+ if (!Selector.assertions[name](element, matches)) {
+ match = false; break;
+ }
+ }
+
+ return match;
+ },
+
+ toString: function() {
+ return this.expression;
+ },
+
+ inspect: function() {
+ return "#<Selector:" + this.expression.inspect() + ">";
+ }
+ });
+
+ Object.extend(Selector, {
+ _cache: { },
+
+ xpath: {
+ descendant: "//*",
+ child: "/*",
+ adjacent: "/following-sibling::*[1]",
+ laterSibling: '/following-sibling::*',
+ tagName: function(m) {
+ if (m[1] == '*') return '';
+ return "[local-name()='" + m[1].toLowerCase() +
+ "' or local-name()='" + m[1].toUpperCase() + "']";
+ },
+ className: "[contains(concat(' ', @class, ' '), ' #{1} ')]",
+ id: "[@id='#{1}']",
+ attrPresence: function(m) {
+ m[1] = m[1].toLowerCase();
+ return new Template("[@#{1}]").evaluate(m);
+ },
+ attr: function(m) {
+ m[1] = m[1].toLowerCase();
+ m[3] = m[5] || m[6];
+ return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
+ },
+ pseudo: function(m) {
+ var h = Selector.xpath.pseudos[m[1]];
+ if (!h) return '';
+ if (Object.isFunction(h)) return h(m);
+ return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
+ },
+ operators: {
+ '=': "[@#{1}='#{3}']",
+ '!=': "[@#{1}!='#{3}']",
+ '^=': "[starts-with(@#{1}, '#{3}')]",
+ '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
+ '*=': "[contains(@#{1}, '#{3}')]",
+ '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
+ '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
+ },
+ pseudos: {
+ 'first-child': '[not(preceding-sibling::*)]',
+ 'last-child': '[not(following-sibling::*)]',
+ 'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
+ 'empty': "[count(*) = 0 and (count(text()) = 0)]",
+ 'checked': "[@checked]",
+ 'disabled': "[(@disabled) and (@type!='hidden')]",
+ 'enabled': "[not(@disabled) and (@type!='hidden')]",
+ 'not': function(m) {
+ var e = m[6], p = Selector.patterns,
+ x = Selector.xpath, le, v;
+
+ var exclusion = [];
+ while (e && le != e && (/\S/).test(e)) {
+ le = e;
+ for (var i in p) {
+ if (m = e.match(p[i])) {
+ v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+ exclusion.push("(" + v.substring(1, v.length - 1) + ")");
+ e = e.replace(m[0], '');
+ break;
+ }
+ }
+ }
+ return "[not(" + exclusion.join(" and ") + ")]";
+ },
+ 'nth-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
+ },
+ 'nth-last-child': function(m) {
+ return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
+ },
+ 'nth-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("position() ", m);
+ },
+ 'nth-last-of-type': function(m) {
+ return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
+ },
+ 'first-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
+ },
+ 'last-of-type': function(m) {
+ m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
+ },
+ 'only-of-type': function(m) {
+ var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
+ },
+ nth: function(fragment, m) {
+ var mm, formula = m[6], predicate;
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ if (mm = formula.match(/^(\d+)$/)) // digit only
+ return '[' + fragment + "= " + mm[1] + ']';
+ if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (mm[1] == "-") mm[1] = -1;
+ var a = mm[1] ? Number(mm[1]) : 1;
+ var b = mm[2] ? Number(mm[2]) : 0;
+ predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
+ "((#{fragment} - #{b}) div #{a} >= 0)]";
+ return new Template(predicate).evaluate({
+ fragment: fragment, a: a, b: b });
+ }
+ }
+ }
+ },
+
+ criteria: {
+ tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
+ className: 'n = h.className(n, r, "#{1}", c); c = false;',
+ id: 'n = h.id(n, r, "#{1}", c); c = false;',
+ attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
+ attr: function(m) {
+ m[3] = (m[5] || m[6]);
+ return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
+ },
+ pseudo: function(m) {
+ if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
+ return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
+ },
+ descendant: 'c = "descendant";',
+ child: 'c = "child";',
+ adjacent: 'c = "adjacent";',
+ laterSibling: 'c = "laterSibling";'
+ },
+
+ patterns: {
+ // combinators must be listed first
+ // (and descendant needs to be last combinator)
+ laterSibling: /^\s*~\s*/,
+ child: /^\s*>\s*/,
+ adjacent: /^\s*\+\s*/,
+ descendant: /^\s/,
+
+ // selectors follow
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
+ id: /^#([\w\-\*]+)(\b|$)/,
+ className: /^\.([\w\-\*]+)(\b|$)/,
+ pseudo:
+ /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
+ attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
+ },
+
+ // for Selector.match and Element#match
+ assertions: {
+ tagName: function(element, matches) {
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ },
+
+ className: function(element, matches) {
+ return Element.hasClassName(element, matches[1]);
+ },
+
+ id: function(element, matches) {
+ return element.id === matches[1];
+ },
+
+ attrPresence: function(element, matches) {
+ return Element.hasAttribute(element, matches[1]);
+ },
+
+ attr: function(element, matches) {
+ var nodeValue = Element.readAttribute(element, matches[1]);
+ return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
+ }
+ },
+
+ handlers: {
+ // UTILITY FUNCTIONS
+ // joins two collections
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ a.push(node);
+ return a;
+ },
+
+ // marks an array of nodes for counting
+ mark: function(nodes) {
+ var _true = Prototype.emptyFunction;
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = _true;
+ return nodes;
+ },
+
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node._countedByPrototype = undefined;
+ return nodes;
+ },
+
+ // mark each child node with its position (for nth calls)
+ // "ofType" flag indicates whether we're indexing for nth-of-type
+ // rather than nth-child
+ index: function(parentNode, reverse, ofType) {
+ parentNode._countedByPrototype = Prototype.emptyFunction;
+ if (reverse) {
+ for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
+ var node = nodes[i];
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ } else {
+ for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
+ if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
+ }
+ },
+
+ // filters out duplicates and extends all nodes
+ unique: function(nodes) {
+ if (nodes.length == 0) return nodes;
+ var results = [], n;
+ for (var i = 0, l = nodes.length; i < l; i++)
+ if (!(n = nodes[i])._countedByPrototype) {
+ n._countedByPrototype = Prototype.emptyFunction;
+ results.push(Element.extend(n));
+ }
+ return Selector.handlers.unmark(results);
+ },
+
+ // COMBINATOR FUNCTIONS
+ descendant: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName('*'));
+ return results;
+ },
+
+ child: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ for (var j = 0, child; child = node.childNodes[j]; j++)
+ if (child.nodeType == 1 && child.tagName != '!') results.push(child);
+ }
+ return results;
+ },
+
+ adjacent: function(nodes) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ var next = this.nextElementSibling(node);
+ if (next) results.push(next);
+ }
+ return results;
+ },
+
+ laterSibling: function(nodes) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ h.concat(results, Element.nextSiblings(node));
+ return results;
+ },
+
+ nextElementSibling: function(node) {
+ while (node = node.nextSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ previousElementSibling: function(node) {
+ while (node = node.previousSibling)
+ if (node.nodeType == 1) return node;
+ return null;
+ },
+
+ // TOKEN FUNCTIONS
+ tagName: function(nodes, root, tagName, combinator) {
+ var uTagName = tagName.toUpperCase();
+ var results = [], h = Selector.handlers;
+ if (nodes) {
+ if (combinator) {
+ // fastlane for ordinary descendant combinators
+ if (combinator == "descendant") {
+ for (var i = 0, node; node = nodes[i]; i++)
+ h.concat(results, node.getElementsByTagName(tagName));
+ return results;
+ } else nodes = this[combinator](nodes);
+ if (tagName == "*") return nodes;
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.tagName.toUpperCase() === uTagName) results.push(node);
+ return results;
+ } else return root.getElementsByTagName(tagName);
+ },
+
+ id: function(nodes, root, id, combinator) {
+ var targetNode = $(id), h = Selector.handlers;
+ if (!targetNode) return [];
+ if (!nodes && root == document) return [targetNode];
+ if (nodes) {
+ if (combinator) {
+ if (combinator == 'child') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (targetNode.parentNode == node) return [targetNode];
+ } else if (combinator == 'descendant') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.descendantOf(targetNode, node)) return [targetNode];
+ } else if (combinator == 'adjacent') {
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Selector.handlers.previousElementSibling(targetNode) == node)
+ return [targetNode];
+ } else nodes = h[combinator](nodes);
+ }
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node == targetNode) return [targetNode];
+ return [];
+ }
+ return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
+ },
+
+ className: function(nodes, root, className, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ return Selector.handlers.byClassName(nodes, root, className);
+ },
+
+ byClassName: function(nodes, root, className) {
+ if (!nodes) nodes = Selector.handlers.descendant([root]);
+ var needle = ' ' + className + ' ';
+ for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
+ nodeClassName = node.className;
+ if (nodeClassName.length == 0) continue;
+ if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
+ results.push(node);
+ }
+ return results;
+ },
+
+ attrPresence: function(nodes, root, attr, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var results = [];
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (Element.hasAttribute(node, attr)) results.push(node);
+ return results;
+ },
+
+ attr: function(nodes, root, attr, value, operator, combinator) {
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ var handler = Selector.operators[operator], results = [];
+ for (var i = 0, node; node = nodes[i]; i++) {
+ var nodeValue = Element.readAttribute(node, attr);
+ if (nodeValue === null) continue;
+ if (handler(nodeValue, value)) results.push(node);
+ }
+ return results;
+ },
+
+ pseudo: function(nodes, name, value, root, combinator) {
+ if (nodes && combinator) nodes = this[combinator](nodes);
+ if (!nodes) nodes = root.getElementsByTagName("*");
+ return Selector.pseudos[name](nodes, value, root);
+ }
+ },
+
+ pseudos: {
+ 'first-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.previousElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'last-child': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ if (Selector.handlers.nextElementSibling(node)) continue;
+ results.push(node);
+ }
+ return results;
+ },
+ 'only-child': function(nodes, value, root) {
+ var h = Selector.handlers;
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
+ results.push(node);
+ return results;
+ },
+ 'nth-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root);
+ },
+ 'nth-last-child': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true);
+ },
+ 'nth-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, false, true);
+ },
+ 'nth-last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, formula, root, true, true);
+ },
+ 'first-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, false, true);
+ },
+ 'last-of-type': function(nodes, formula, root) {
+ return Selector.pseudos.nth(nodes, "1", root, true, true);
+ },
+ 'only-of-type': function(nodes, formula, root) {
+ var p = Selector.pseudos;
+ return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
+ },
+
+ // handles the an+b logic
+ getIndices: function(a, b, total) {
+ if (a == 0) return b > 0 ? [b] : [];
+ return $R(1, total).inject([], function(memo, i) {
+ if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
+ return memo;
+ });
+ },
+
+ // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
+ nth: function(nodes, formula, root, reverse, ofType) {
+ if (nodes.length == 0) return [];
+ if (formula == 'even') formula = '2n+0';
+ if (formula == 'odd') formula = '2n+1';
+ var h = Selector.handlers, results = [], indexed = [], m;
+ h.mark(nodes);
+ for (var i = 0, node; node = nodes[i]; i++) {
+ if (!node.parentNode._countedByPrototype) {
+ h.index(node.parentNode, reverse, ofType);
+ indexed.push(node.parentNode);
+ }
+ }
+ if (formula.match(/^\d+$/)) { // just a number
+ formula = Number(formula);
+ for (var i = 0, node; node = nodes[i]; i++)
+ if (node.nodeIndex == formula) results.push(node);
+ } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
+ if (m[1] == "-") m[1] = -1;
+ var a = m[1] ? Number(m[1]) : 1;
+ var b = m[2] ? Number(m[2]) : 0;
+ var indices = Selector.pseudos.getIndices(a, b, nodes.length);
+ for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
+ for (var j = 0; j < l; j++)
+ if (node.nodeIndex == indices[j]) results.push(node);
+ }
+ }
+ h.unmark(nodes);
+ h.unmark(indexed);
+ return results;
+ },
+
+ 'empty': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++) {
+ // IE treats comments as element nodes
+ if (node.tagName == '!' || node.firstChild) continue;
+ results.push(node);
+ }
+ return results;
+ },
+
+ 'not': function(nodes, selector, root) {
+ var h = Selector.handlers, selectorType, m;
+ var exclusions = new Selector(selector).findElements(root);
+ h.mark(exclusions);
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node._countedByPrototype) results.push(node);
+ h.unmark(exclusions);
+ return results;
+ },
+
+ 'enabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (!node.disabled && (!node.type || node.type !== 'hidden'))
+ results.push(node);
+ return results;
+ },
+
+ 'disabled': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.disabled) results.push(node);
+ return results;
+ },
+
+ 'checked': function(nodes, value, root) {
+ for (var i = 0, results = [], node; node = nodes[i]; i++)
+ if (node.checked) results.push(node);
+ return results;
+ }
+ },
+
+ operators: {
+ '=': function(nv, v) { return nv == v; },
+ '!=': function(nv, v) { return nv != v; },
+ '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
+ '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
+ '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
+ '$=': function(nv, v) { return nv.endsWith(v); },
+ '*=': function(nv, v) { return nv.include(v); },
+ '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
+ '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
+ '-').include('-' + (v || "").toUpperCase() + '-'); }
+ },
+
+ split: function(expression) {
+ var expressions = [];
+ expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
+ expressions.push(m[1].strip());
+ });
+ return expressions;
+ },
+
+ matchElements: function(elements, expression) {
+ var matches = $$(expression), h = Selector.handlers;
+ h.mark(matches);
+ for (var i = 0, results = [], element; element = elements[i]; i++)
+ if (element._countedByPrototype) results.push(element);
+ h.unmark(matches);
+ return results;
+ },
+
+ findElement: function(elements, expression, index) {
+ if (Object.isNumber(expression)) {
+ index = expression; expression = false;
+ }
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ expressions = Selector.split(expressions.join(','));
+ var results = [], h = Selector.handlers;
+ for (var i = 0, l = expressions.length, selector; i < l; i++) {
+ selector = new Selector(expressions[i].strip());
+ h.concat(results, selector.findElements(element));
+ }
+ return (l > 1) ? h.unique(results) : results;
+ }
+ });
+
+ if (Prototype.Browser.IE) {
+ Object.extend(Selector.handlers, {
+ // IE returns comment nodes on getElementsByTagName("*").
+ // Filter them out.
+ concat: function(a, b) {
+ for (var i = 0, node; node = b[i]; i++)
+ if (node.tagName !== "!") a.push(node);
+ return a;
+ },
+
+ // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
+ unmark: function(nodes) {
+ for (var i = 0, node; node = nodes[i]; i++)
+ node.removeAttribute('_countedByPrototype');
+ return nodes;
+ }
+ });
+ }
+
+ function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+ }
+ var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ },
+
+ serializeElements: function(elements, options) {
+ if (typeof options != 'object') options = { hash: !!options };
+ else if (Object.isUndefined(options.hash)) options.hash = true;
+ var key, value, submitted = false, submit = options.submit;
+
+ var data = elements.inject({ }, function(result, element) {
+ if (!element.disabled && element.name) {
+ key = element.name; value = $(element).getValue();
+ if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
+ submit !== false && (!submit || key == submit) && (submitted = true)))) {
+ if (key in result) {
+ // a key is already present; construct an array of values
+ if (!Object.isArray(result[key])) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return options.hash ? data : Object.toQueryString(data);
+ }
+ };
+
+ Form.Methods = {
+ serialize: function(form, options) {
+ return Form.serializeElements(Form.getElements(form), options);
+ },
+
+ getElements: function(form) {
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('disable');
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ Form.getElements(form).invoke('enable');
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ var elements = $(form).getElements().findAll(function(element) {
+ return 'hidden' != element.type && !element.disabled;
+ });
+ var firstByIndex = elements.findAll(function(element) {
+ return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
+ }).sortBy(function(element) { return element.tabIndex }).first();
+
+ return firstByIndex ? firstByIndex : elements.find(function(element) {
+ return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ },
+
+ request: function(form, options) {
+ form = $(form), options = Object.clone(options || { });
+
+ var params = options.parameters, action = form.readAttribute('action') || '';
+ if (action.blank()) action = window.location.href;
+ options.parameters = form.serialize(true);
+
+ if (params) {
+ if (Object.isString(params)) params = params.toQueryParams();
+ Object.extend(options.parameters, params);
+ }
+
+ if (form.hasAttribute('method') && !options.method)
+ options.method = form.method;
+
+ return new Ajax.Request(action, options);
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+ };
+
+ Form.Element.Methods = {
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = { };
+ pair[element.name] = value;
+ return Object.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ setValue: function(element, value) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ Form.Element.Serializers[method](element, value);
+ return element;
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ try {
+ element.focus();
+ if (element.select && (element.tagName.toLowerCase() != 'input' ||
+ !['button', 'reset', 'submit'].include(element.type)))
+ element.select();
+ } catch (e) { }
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.disabled = false;
+ return element;
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ var Field = Form.Element;
+ var $F = Form.Element.Methods.getValue;
+
+ /*--------------------------------------------------------------------------*/
+
+ Form.Element.Serializers = {
+ input: function(element, value) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element, value);
+ default:
+ return Form.Element.Serializers.textarea(element, value);
+ }
+ },
+
+ inputSelector: function(element, value) {
+ if (Object.isUndefined(value)) return element.checked ? element.value : null;
+ else element.checked = !!value;
+ },
+
+ textarea: function(element, value) {
+ if (Object.isUndefined(value)) return element.value;
+ else element.value = value;
+ },
+
+ select: function(element, value) {
+ if (Object.isUndefined(value))
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ else {
+ var opt, currentValue, single = !Object.isArray(value);
+ for (var i = 0, length = element.length; i < length; i++) {
+ opt = element.options[i];
+ currentValue = this.optionValue(opt);
+ if (single) {
+ if (currentValue == value) {
+ opt.selected = true;
+ return;
+ }
+ }
+ else opt.selected = value.include(currentValue);
+ }
+ }
+ },
+
+ selectOne: function(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
+ },
+
+ selectMany: function(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(this.optionValue(opt));
+ }
+ return values;
+ },
+
+ optionValue: function(opt) {
+ // extend element because hasAttribute may not be native
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
+ initialize: function($super, element, frequency, callback) {
+ $super(callback, frequency);
+ this.element = $(element);
+ this.lastValue = this.getValue();
+ },
+
+ execute: function() {
+ var value = this.getValue();
+ if (Object.isString(this.lastValue) && Object.isString(value) ?
+ this.lastValue != value : String(this.lastValue) != String(value)) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+ });
+
+ Form.Element.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+ });
+
+ Form.Observer = Class.create(Abstract.TimedObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+ });
+
+ /*--------------------------------------------------------------------------*/
+
+ Abstract.EventObserver = Class.create({
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback, this);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+ });
+
+ Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+ });
+
+ Form.EventObserver = Class.create(Abstract.EventObserver, {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+ });
+ if (!window.Event) var Event = { };
+
+ Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+ KEY_INSERT: 45,
+
+ cache: { },
+
+ relatedTarget: function(event) {
+ var element;
+ switch(event.type) {
+ case 'mouseover': element = event.fromElement; break;
+ case 'mouseout': element = event.toElement; break;
+ default: return null;
+ }
+ return Element.extend(element);
+ }
+ });
+
+ Event.Methods = (function() {
+ var isButton;
+
+ if (Prototype.Browser.IE) {
+ var buttonMap = { 0: 1, 1: 4, 2: 2 };
+ isButton = function(event, code) {
+ return event.button == buttonMap[code];
+ };
+
+ } else if (Prototype.Browser.WebKit) {
+ isButton = function(event, code) {
+ switch (code) {
+ case 0: return event.which == 1 && !event.metaKey;
+ case 1: return event.which == 1 && event.metaKey;
+ default: return false;
+ }
+ };
+
+ } else {
+ isButton = function(event, code) {
+ return event.which ? (event.which === code + 1) : (event.button === code);
+ };
+ }
+
+ return {
+ isLeftClick: function(event) { return isButton(event, 0) },
+ isMiddleClick: function(event) { return isButton(event, 1) },
+ isRightClick: function(event) { return isButton(event, 2) },
+
+ element: function(event) {
+ event = Event.extend(event);
+
+ var node = event.target,
+ type = event.type,
+ currentTarget = event.currentTarget;
+
+ if (currentTarget && currentTarget.tagName) {
+ // Firefox screws up the "click" event when moving between radio buttons
+ // via arrow keys. It also screws up the "load" and "error" events on images,
+ // reporting the document as the target instead of the original image.
+ if (type === 'load' || type === 'error' ||
+ (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
+ && currentTarget.type === 'radio'))
+ node = currentTarget;
+ }
+ if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
+ return Element.extend(node);
+ },
+
+ findElement: function(event, expression) {
+ var element = Event.element(event);
+ if (!expression) return element;
+ var elements = [element].concat(element.ancestors());
+ return Selector.findElement(elements, expression, 0);
+ },
+
+ pointer: function(event) {
+ var docElement = document.documentElement,
+ body = document.body || { scrollLeft: 0, scrollTop: 0 };
+ return {
+ x: event.pageX || (event.clientX +
+ (docElement.scrollLeft || body.scrollLeft) -
+ (docElement.clientLeft || 0)),
+ y: event.pageY || (event.clientY +
+ (docElement.scrollTop || body.scrollTop) -
+ (docElement.clientTop || 0))
+ };
+ },
+
+ pointerX: function(event) { return Event.pointer(event).x },
+ pointerY: function(event) { return Event.pointer(event).y },
+
+ stop: function(event) {
+ Event.extend(event);
+ event.preventDefault();
+ event.stopPropagation();
+ event.stopped = true;
+ }
+ };
+ })();
+
+ Event.extend = (function() {
+ var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
+ m[name] = Event.Methods[name].methodize();
+ return m;
+ });
+
+ if (Prototype.Browser.IE) {
+ Object.extend(methods, {
+ stopPropagation: function() { this.cancelBubble = true },
+ preventDefault: function() { this.returnValue = false },
+ inspect: function() { return "[object Event]" }
+ });
+
+ return function(event) {
+ if (!event) return false;
+ if (event._extendedByPrototype) return event;
+
+ event._extendedByPrototype = Prototype.emptyFunction;
+ var pointer = Event.pointer(event);
+ Object.extend(event, {
+ target: event.srcElement,
+ relatedTarget: Event.relatedTarget(event),
+ pageX: pointer.x,
+ pageY: pointer.y
+ });
+ return Object.extend(event, methods);
+ };
+
+ } else {
+ Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
+ Object.extend(Event.prototype, methods);
+ return Prototype.K;
+ }
+ })();
+
+ Object.extend(Event, (function() {
+ var cache = Event.cache;
+
+ function getEventID(element) {
+ if (element._prototypeEventID) return element._prototypeEventID[0];
+ arguments.callee.id = arguments.callee.id || 1;
+ return element._prototypeEventID = [++arguments.callee.id];
+ }
+
+ function getDOMEventName(eventName) {
+ if (eventName && eventName.include(':')) return "dataavailable";
+ return eventName;
+ }
+
+ function getCacheForID(id) {
+ return cache[id] = cache[id] || { };
+ }
+
+ function getWrappersForEventName(id, eventName) {
+ var c = getCacheForID(id);
+ return c[eventName] = c[eventName] || [];
+ }
+
+ function createWrapper(element, eventName, handler) {
+ var id = getEventID(element);
+ var c = getWrappersForEventName(id, eventName);
+ if (c.pluck("handler").include(handler)) return false;
+
+ var wrapper = function(event) {
+ if (!Event || !Event.extend ||
+ (event.eventName && event.eventName != eventName))
+ return false;
+
+ Event.extend(event);
+ handler.call(element, event);
+ };
+
+ wrapper.handler = handler;
+ c.push(wrapper);
+ return wrapper;
+ }
+
+ function findWrapper(id, eventName, handler) {
+ var c = getWrappersForEventName(id, eventName);
+ return c.find(function(wrapper) { return wrapper.handler == handler });
+ }
+
+ function destroyWrapper(id, eventName, handler) {
+ var c = getCacheForID(id);
+ if (!c[eventName]) return false;
+ c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+ }
+
+ function destroyCache() {
+ for (var id in cache)
+ for (var eventName in cache[id])
+ cache[id][eventName] = null;
+ }
+
+
+ // Internet Explorer needs to remove event handlers on page unload
+ // in order to avoid memory leaks.
+ if (window.attachEvent) {
+ window.attachEvent("onunload", destroyCache);
+ }
+
+ // Safari has a dummy event handler on page unload so that it won't
+ // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
+ // object when page is returned to via the back button using its bfcache.
+ if (Prototype.Browser.WebKit) {
+ window.addEventListener('unload', Prototype.emptyFunction, false);
+ }
+
+ return {
+ observe: function(element, eventName, handler) {
+ element = $(element);
+ var name = getDOMEventName(eventName);
+
+ var wrapper = createWrapper(element, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.addEventListener) {
+ element.addEventListener(name, wrapper, false);
+ } else {
+ element.attachEvent("on" + name, wrapper);
+ }
+
+ return element;
+ },
+
+ stopObserving: function(element, eventName, handler) {
+ element = $(element);
+ var id = getEventID(element), name = getDOMEventName(eventName);
+
+ if (!handler && eventName) {
+ getWrappersForEventName(id, eventName).each(function(wrapper) {
+ element.stopObserving(eventName, wrapper.handler);
+ });
+ return element;
+
+ } else if (!eventName) {
+ Object.keys(getCacheForID(id)).each(function(eventName) {
+ element.stopObserving(eventName);
+ });
+ return element;
+ }
+
+ var wrapper = findWrapper(id, eventName, handler);
+ if (!wrapper) return element;
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, wrapper, false);
+ } else {
+ element.detachEvent("on" + name, wrapper);
+ }
+
+ destroyWrapper(id, eventName, handler);
+
+ return element;
+ },
+
+ fire: function(element, eventName, memo) {
+ element = $(element);
+ if (element == document && document.createEvent && !element.dispatchEvent)
+ element = document.documentElement;
+
+ var event;
+ if (document.createEvent) {
+ event = document.createEvent("HTMLEvents");
+ event.initEvent("dataavailable", true, true);
+ } else {
+ event = document.createEventObject();
+ event.eventType = "ondataavailable";
+ }
+
+ event.eventName = eventName;
+ event.memo = memo || { };
+
+ if (document.createEvent) {
+ element.dispatchEvent(event);
+ } else {
+ element.fireEvent(event.eventType, event);
+ }
+
+ return Event.extend(event);
+ }
+ };
+ })());
+
+ Object.extend(Event, Event.Methods);
+
+ Element.addMethods({
+ fire: Event.fire,
+ observe: Event.observe,
+ stopObserving: Event.stopObserving
+ });
+
+ Object.extend(document, {
+ fire: Element.Methods.fire.methodize(),
+ observe: Element.Methods.observe.methodize(),
+ stopObserving: Element.Methods.stopObserving.methodize(),
+ loaded: false
+ });
+
+ (function() {
+ /* Support for the DOMContentLoaded event is based on work by Dan Webb,
+ Matthias Miller, Dean Edwards and John Resig. */
+
+ var timer;
+
+ function fireContentLoadedEvent() {
+ if (document.loaded) return;
+ if (timer) window.clearInterval(timer);
+ document.fire("dom:loaded");
+ document.loaded = true;
+ }
+
+ if (document.addEventListener) {
+ if (Prototype.Browser.WebKit) {
+ timer = window.setInterval(function() {
+ if (/loaded|complete/.test(document.readyState))
+ fireContentLoadedEvent();
+ }, 0);
+
+ Event.observe(window, "load", fireContentLoadedEvent);
+
+ } else {
+ document.addEventListener("DOMContentLoaded",
+ fireContentLoadedEvent, false);
+ }
+
+ } else {
+ document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
+ $("__onDOMContentLoaded").onreadystatechange = function() {
+ if (this.readyState == "complete") {
+ this.onreadystatechange = null;
+ fireContentLoadedEvent();
+ }
+ };
+ }
+ })();
+ /*------------------------------- DEPRECATED -------------------------------*/
+
+ Hash.toQueryString = Object.toQueryString;
+
+ var Toggle = { display: Element.toggle };
+
+ Element.Methods.childOf = Element.Methods.descendantOf;
+
+ var Insertion = {
+ Before: function(element, content) {
+ return Element.insert(element, {before:content});
+ },
+
+ Top: function(element, content) {
+ return Element.insert(element, {top:content});
+ },
+
+ Bottom: function(element, content) {
+ return Element.insert(element, {bottom:content});
+ },
+
+ After: function(element, content) {
+ return Element.insert(element, {after:content});
+ }
+ };
+
+ var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
+
+ // This should be moved to script.aculo.us; notice the deprecated methods
+ // further below, that map to the newer Element methods.
+ var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = Element.cumulativeScrollOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = Element.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ // Deprecation layer -- use newer Element methods now (1.5.2).
+
+ cumulativeOffset: Element.Methods.cumulativeOffset,
+
+ positionedOffset: Element.Methods.positionedOffset,
+
+ absolutize: function(element) {
+ Position.prepare();
+ return Element.absolutize(element);
+ },
+
+ relativize: function(element) {
+ Position.prepare();
+ return Element.relativize(element);
+ },
+
+ realOffset: Element.Methods.cumulativeScrollOffset,
+
+ offsetParent: Element.Methods.getOffsetParent,
+
+ page: Element.Methods.viewportOffset,
+
+ clone: function(source, target, options) {
+ options = options || { };
+ return Element.clonePosition(target, source, options);
+ }
+ };
+
+ /*--------------------------------------------------------------------------*/
+
+ if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
+ function iter(name) {
+ return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
+ }
+
+ instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
+ function(element, className) {
+ className = className.toString().strip();
+ var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
+ return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
+ } : function(element, className) {
+ className = className.toString().strip();
+ var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
+ if (!classNames && !className) return elements;
+
+ var nodes = $(element).getElementsByTagName('*');
+ className = ' ' + className + ' ';
+
+ for (var i = 0, child, cn; child = nodes[i]; i++) {
+ if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
+ (classNames && classNames.all(function(name) {
+ return !name.toString().blank() && cn.include(' ' + name + ' ');
+ }))))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ };
+
+ return function(className, parentElement) {
+ return $(parentElement || document.body).getElementsByClassName(className);
+ };
+ }(Element.Methods);
+
+ /*--------------------------------------------------------------------------*/
+
+ Element.ClassNames = Class.create();
+ Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+ };
+
+ Object.extend(Element.ClassNames.prototype, Enumerable);
+
+ /*--------------------------------------------------------------------------*/
+
+ Element.addMethods();
+ var search_index = [
+ { method: '<=>', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000050"><span class="method_name">&lt;=&gt;</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: '[]', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000011"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: '[]', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000031"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: '[]', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000047"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: '[]=', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000048"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: '[]=', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000012"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: '[]=', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000032"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: 'active?', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000016"><span class="method_name">active?</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'add', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000060"><span class="method_name">add</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'busy?', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000057"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'busy?', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000040"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'busy?', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000004"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'channels', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000042"><span class="method_name">channels</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'close', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000074"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'close', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000018"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'close', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000041"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'close', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000058"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'concat', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000061"><span class="method_name">concat</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'connect!', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000003"><span class="method_name">connect!</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'delegate_to', module: 'net::ssh::multi::channelproxy', html: '<a href="classes/Net/SSH/Multi/ChannelProxy.html#M000028"><span class="method_name">delegate_to</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a>' },
+ { method: 'each', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000033"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: 'each', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000010"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'each', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000062"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'eof!', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000019"><span class="method_name">eof!</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'evaluate!', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000034"><span class="method_name">evaluate!</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: 'exec', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000008"><span class="method_name">exec</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'exec', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000013"><span class="method_name">exec</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'fail!', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000055"><span class="method_name">fail!</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'failed?', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000054"><span class="method_name">failed?</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'first', module: 'net::ssh::multi::subsession', html: '<a href="classes/Net/SSH/Multi/Subsession.html#M000080"><span class="method_name">first</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a>' },
+ { method: 'flatten', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000064"><span class="method_name">flatten</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'group', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000067"><span class="method_name">group</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'hash', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000051"><span class="method_name">hash</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'inspect', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000053"><span class="method_name">inspect</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'listeners', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000045"><span class="method_name">listeners</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'loop', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000075"><span class="method_name">loop</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'loop_forever', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000076"><span class="method_name">loop_forever</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'master', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000002"><span class="method_name">master</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'method_missing', module: 'net::ssh::multi::channelproxy', html: '<a href="classes/Net/SSH/Multi/ChannelProxy.html#M000029"><span class="method_name">method_missing</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000059"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::channelproxy', html: '<a href="classes/Net/SSH/Multi/ChannelProxy.html#M000027"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000036"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000066"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000009"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::subsession', html: '<a href="classes/Net/SSH/Multi/Subsession.html#M000078"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000046"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'new', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000030"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: 'on', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000073"><span class="method_name">on</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'on_close', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000023"><span class="method_name">on_close</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_data', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000020"><span class="method_name">on_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_eof', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000024"><span class="method_name">on_eof</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_extended_data', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000021"><span class="method_name">on_extended_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_open_failed', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000025"><span class="method_name">on_open_failed</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_process', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000022"><span class="method_name">on_process</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'on_request', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000026"><span class="method_name">on_request</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'open_channel', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000038"><span class="method_name">open_channel</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'open_channel', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000007"><span class="method_name">open_channel</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'port', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000049"><span class="method_name">port</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'postprocess', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000044"><span class="method_name">postprocess</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'preprocess', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000043"><span class="method_name">preprocess</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'process', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000077"><span class="method_name">process</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'replace_with', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000037"><span class="method_name">replace_with</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'request_pty', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000014"><span class="method_name">request_pty</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'select', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000063"><span class="method_name">select</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'send_data', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000015"><span class="method_name">send_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'send_global_request', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000006"><span class="method_name">send_global_request</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'send_global_request', module: 'net::ssh::multi::pendingconnection', html: '<a href="classes/Net/SSH/Multi/PendingConnection.html#M000039"><span class="method_name">send_global_request</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a>' },
+ { method: 'servers', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000070"><span class="method_name">servers</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'servers_for', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000071"><span class="method_name">servers_for</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'session', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000056"><span class="method_name">session</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'sessions', module: 'net::ssh::multi::sessionactions', html: '<a href="classes/Net/SSH/Multi/SessionActions.html#M000005"><span class="method_name">sessions</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a>' },
+ { method: 'slice', module: 'net::ssh::multi::subsession', html: '<a href="classes/Net/SSH/Multi/Subsession.html#M000079"><span class="method_name">slice</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a>' },
+ { method: 'start', module: 'net::ssh::multi', html: '<a href="classes/Net/SSH/Multi.html#M000001"><span class="method_name">start</span> <span class="module_name">(Net::SSH::Multi)</span></a>' },
+ { method: 'to_ary', module: 'net::ssh::multi::dynamicserver', html: '<a href="classes/Net/SSH/Multi/DynamicServer.html#M000035"><span class="method_name">to_ary</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a>' },
+ { method: 'to_ary', module: 'net::ssh::multi::serverlist', html: '<a href="classes/Net/SSH/Multi/ServerList.html#M000065"><span class="method_name">to_ary</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a>' },
+ { method: 'to_s', module: 'net::ssh::multi::server', html: '<a href="classes/Net/SSH/Multi/Server.html#M000052"><span class="method_name">to_s</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a>' },
+ { method: 'use', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000069"><span class="method_name">use</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'via', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000068"><span class="method_name">via</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ { method: 'wait', module: 'net::ssh::multi::channel', html: '<a href="classes/Net/SSH/Multi/Channel.html#M000017"><span class="method_name">wait</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a>' },
+ { method: 'with', module: 'net::ssh::multi::session', html: '<a href="classes/Net/SSH/Multi/Session.html#M000072"><span class="method_name">with</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a>' },
+ ]
+ $(document).observe('dom:loaded', function() {
+ // Setup search-during-typing.
+ new Form.Element.Observer('search', 0.3, function(element, value) {
+ performSearch();
+ });
+
+ // Remove the default search box value when the user puts the focus on
+ // the search box for the first time.
+ var search_box = $('search');
+ if ($F('search') == 'Enter search terms...') {
+ search_box.observe('focus', function() {
+ if (search_box.hasClassName('untouched')) {
+ search_box.removeClassName('untouched');
+ search_box.value = '';
+ }
+ });
+ } else {
+ search_box.removeClassName('untouched');
+ }
+
+ search_box.insert({
+ after: new Element('span', { 'class': 'clear_button' }).update('x').observe('click', function(e) {
+ e.stopPropagation()
+ search_box.setValue('')
+ search_box.focus()
+ })
+ })
+ });
+
+ function searchInIndex(query) {
+ var i;
+ var results = [];
+ query = query.toLowerCase();
+ for (i = 0; i < search_index.length; i++) {
+ if (search_index[i].method.indexOf(query) != -1) {
+ results.push(search_index[i]);
+ }
+ }
+ return results;
+ }
+
+ function buildHtmlForResults(results) {
+ var html = "";
+ var i;
+ for (i = 0; i < results.length; i++) {
+ html += '<li>' + results[i].html + '</li>';
+ }
+ return html;
+ }
+
+ function performSearch() {
+ var query = $F('search');
+ if (query == '') {
+ $('index-entries').show();
+ $('search-results').hide();
+ } else {
+ var results = searchInIndex(query);
+ $('search-results').update(buildHtmlForResults(results));
+ $('index-entries').hide();
+ $('search-results').show();
+ }
+ return false;
+ }
+ </script>
+ <form onsubmit='return performSearch()'>
+ <input class='untouched' id='search' type='text' value='Enter search terms...'>
+ </form>
+ <ol class='methods' id='search-results' style='display: none'></ol>
+ <ol class='methods' id='index-entries'>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000050"><span class="method_name">&lt;=&gt;</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000011"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000031"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000047"><span class="method_name">[]</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000048"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000012"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000032"><span class="method_name">[]=</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000016"><span class="method_name">active?</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000060"><span class="method_name">add</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000057"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000040"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000004"><span class="method_name">busy?</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000042"><span class="method_name">channels</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000074"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000018"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000041"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000058"><span class="method_name">close</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000061"><span class="method_name">concat</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000003"><span class="method_name">connect!</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ChannelProxy.html#M000028"><span class="method_name">delegate_to</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000033"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000010"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000062"><span class="method_name">each</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000019"><span class="method_name">eof!</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000034"><span class="method_name">evaluate!</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000008"><span class="method_name">exec</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000013"><span class="method_name">exec</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000055"><span class="method_name">fail!</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000054"><span class="method_name">failed?</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Subsession.html#M000080"><span class="method_name">first</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000064"><span class="method_name">flatten</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000067"><span class="method_name">group</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000051"><span class="method_name">hash</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000053"><span class="method_name">inspect</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000045"><span class="method_name">listeners</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000075"><span class="method_name">loop</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000076"><span class="method_name">loop_forever</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000002"><span class="method_name">master</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ChannelProxy.html#M000029"><span class="method_name">method_missing</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000059"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ChannelProxy.html#M000027"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::ChannelProxy)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000036"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000066"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000009"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Subsession.html#M000078"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000046"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000030"><span class="method_name">new</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000073"><span class="method_name">on</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000023"><span class="method_name">on_close</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000020"><span class="method_name">on_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000024"><span class="method_name">on_eof</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000021"><span class="method_name">on_extended_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000025"><span class="method_name">on_open_failed</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000022"><span class="method_name">on_process</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000026"><span class="method_name">on_request</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000038"><span class="method_name">open_channel</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000007"><span class="method_name">open_channel</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000049"><span class="method_name">port</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000044"><span class="method_name">postprocess</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000043"><span class="method_name">preprocess</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000077"><span class="method_name">process</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000037"><span class="method_name">replace_with</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000014"><span class="method_name">request_pty</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000063"><span class="method_name">select</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000015"><span class="method_name">send_data</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000006"><span class="method_name">send_global_request</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/PendingConnection.html#M000039"><span class="method_name">send_global_request</span> <span class="module_name">(Net::SSH::Multi::PendingConnection)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000070"><span class="method_name">servers</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000071"><span class="method_name">servers_for</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000056"><span class="method_name">session</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/SessionActions.html#M000005"><span class="method_name">sessions</span> <span class="module_name">(Net::SSH::Multi::SessionActions)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Subsession.html#M000079"><span class="method_name">slice</span> <span class="module_name">(Net::SSH::Multi::Subsession)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi.html#M000001"><span class="method_name">start</span> <span class="module_name">(Net::SSH::Multi)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/DynamicServer.html#M000035"><span class="method_name">to_ary</span> <span class="module_name">(Net::SSH::Multi::DynamicServer)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/ServerList.html#M000065"><span class="method_name">to_ary</span> <span class="module_name">(Net::SSH::Multi::ServerList)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Server.html#M000052"><span class="method_name">to_s</span> <span class="module_name">(Net::SSH::Multi::Server)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000069"><span class="method_name">use</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000068"><span class="method_name">via</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Channel.html#M000017"><span class="method_name">wait</span> <span class="module_name">(Net::SSH::Multi::Channel)</span></a></li>
+ <li><a href="classes/Net/SSH/Multi/Session.html#M000072"><span class="method_name">with</span> <span class="module_name">(Net::SSH::Multi::Session)</span></a></li>
+ </ol>
+ </div>
+ </body>
+</html>
diff --git a/index.html b/index.html
index 6005f40..bc56304 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,15 @@
-Docs
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
+<html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
+ <head>
+ <title>Control multiple Net::SSH connections via a single interface.</title>
+ <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
+ </head>
+ <frameset border='1' bordercolor='gray' cols='20%, *' frameborder='1'>
+ <frameset rows='15%, 35%, 50%'>
+ <frame name='Files' src='fr_file_index.html' title='Files'></frame>
+ <frame name='Classes' src='fr_class_index.html'></frame>
+ <frame name='Methods' src='fr_method_index.html'></frame>
+ </frameset>
+ <frame name='docwin' src='files/README_rdoc.html'></frame>
+ </frameset>
+</html>
diff --git a/rdoc-style.css b/rdoc-style.css
new file mode 100644
index 0000000..577d952
--- /dev/null
+++ b/rdoc-style.css
@@ -0,0 +1,328 @@
+html, body {
+ height: 100%; }
+
+body {
+ font-family: Lucida Grande, Verdana, Arial, Helvetica, sans-serif;
+ font-size: 90%;
+ margin: 0;
+ padding: 0;
+ background: white;
+ color: black; }
+
+#wrapper {
+ min-height: 100%;
+ height: auto !important;
+ height: 100%;
+ margin: 0 auto -43px; }
+
+#footer-push {
+ height: 43px; }
+
+div.header, #footer {
+ background: #eee; }
+
+#footer {
+ border-top: 1px solid silver;
+ margin-top: 12px;
+ padding: 0 2em;
+ line-height: 30px;
+ text-align: center;
+ font-variant: small-caps;
+ font-size: 95%; }
+
+.clearing:after {
+ content: ".";
+ visibility: hidden;
+ height: 0;
+ display: block;
+ clear: both; }
+* html .clearing {
+ height: 1px; }
+.clearing *:first-child + html {
+ overflow: hidden; }
+
+h1, h2, h3, h4, h5, h6 {
+ margin: 0;
+ font-weight: normal; }
+
+a {
+ color: #0b3e71; }
+ a:hover {
+ background: #336699;
+ text-decoration: none;
+ color: #eef; }
+
+#diagram img {
+ border: 0; }
+
+#description a, .method .description a, .header a {
+ color: #336699; }
+ #description a:hover, .method .description a:hover, .header a:hover {
+ color: #eee; }
+#description h1 a, #description h2 a, #description h3 a, #description h4 a, #description h5 a, #description h6 a, .method .description h1 a, .method .description h2 a, .method .description h3 a, .method .description h4 a, .method .description h5 a, .method .description h6 a, .header h1 a, .header h2 a, .header h3 a, .header h4 a, .header h5 a, .header h6 a {
+ color: #0b3e71; }
+
+ol {
+ margin: 0;
+ padding: 0;
+ list-style: none; }
+ ol li {
+ margin-left: 0;
+ white-space: nowrap; }
+ ol li.other {
+ display: none; }
+
+ol.expanded li.other {
+ display: list-item; }
+
+table {
+ margin-bottom: 1em;
+ font-size: 1em;
+ border-collapse: collapse; }
+ table td, table th {
+ padding: .4em .8em; }
+ table thead {
+ background-color: #e8e8e8; }
+ table thead th {
+ font-variant: small-caps;
+ color: #666666; }
+ table tr {
+ border-bottom: 1px solid silver; }
+
+#index a.show, div.header a.show {
+ text-decoration: underline;
+ font-style: italic;
+ color: #666666; }
+ #index a.show:after, div.header a.show:after {
+ content: " ..."; }
+ #index a.show:hover, div.header a.show:hover {
+ color: black;
+ background: #ffe; }
+
+#index {
+ font: 85%/1.2 Arial, Helvetica, sans-serif; }
+ #index a {
+ text-decoration: none; }
+ #index h1 {
+ padding: .2em .5em .1em;
+ background: #ccc;
+ font: small-caps 1.2em Georgia, serif;
+ color: #333;
+ border-bottom: 1px solid gray; }
+ #index form {
+ margin: 0;
+ padding: 0; }
+ #index form input {
+ margin: .4em 3px 0 .4em;
+ width: 80%; }
+ #index form #search.untouched {
+ color: #777777; }
+ #index form .clear_button {
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ background: #AAA;
+ color: white;
+ padding: 0 5px 1px 5px;
+ cursor: pointer; }
+ #index ol {
+ padding: .4em .5em; }
+ #index ol li {
+ white-space: nowrap; }
+ #index #index-entries li a {
+ padding: 1px 2px; }
+ #index #index-entries.classes {
+ font-size: 1.1em; }
+ #index #index-entries.classes ol {
+ padding: 0; }
+ #index #index-entries.classes span.nodoc {
+ display: none; }
+ #index #index-entries.classes span.nodoc, #index #index-entries.classes a {
+ font-weight: bold; }
+ #index #index-entries.classes .parent {
+ font-weight: normal; }
+ #index #index-entries.methods li, #index #search-results.methods li {
+ margin-bottom: 0.2em; }
+ #index #index-entries.methods li a .method_name, #index #search-results.methods li a .method_name {
+ margin-right: 0.25em; }
+ #index #index-entries.methods li a .module_name, #index #search-results.methods li a .module_name {
+ color: #666666; }
+ #index #index-entries.methods li a:hover .module_name, #index #search-results.methods li a:hover .module_name {
+ color: #ddd; }
+
+#attribute-list .context-item-name {
+ font-weight: bold; }
+
+div.header {
+ font-size: 80%;
+ padding: .5em 2%;
+ font-family: Arial, Helvetica, sans-serif;
+ border-bottom: 1px solid silver; }
+ div.header .name {
+ font-size: 1.6em;
+ font-family: Georgia, serif; }
+ div.header .name .type {
+ color: #666666;
+ font-size: 80%;
+ font-variant: small-caps; }
+ div.header h1.name {
+ font-size: 2.2em; }
+ div.header .paths, div.header .last-update, div.header .parent {
+ color: #666666; }
+ div.header .last-update .datetime {
+ color: #484848; }
+ div.header .parent {
+ margin-top: .3em; }
+ div.header .parent strong {
+ font-weight: normal;
+ color: #484848; }
+
+#content {
+ padding: 12px 2%; }
+ div.class #content {
+ position: relative;
+ width: 72%; }
+ #content pre, #content .method .synopsis {
+ font: 14px Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; }
+ #content pre {
+ color: black;
+ background: #eee;
+ border: 1px solid silver;
+ padding: .5em .8em;
+ overflow: auto; }
+ #content p code, #content p tt, #content li code, #content li tt, #content dl code, #content dl tt {
+ font: 14px Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
+ background: #ffffe3;
+ padding: 2px 3px;
+ line-height: 1.4; }
+ #content h1 code, #content h1 tt, #content h2 code, #content h2 tt, #content h3 code, #content h3 tt, #content h4 code, #content h4 tt, #content h5 code, #content h5 tt, #content h6 code, #content h6 tt {
+ font-size: 1.1em; }
+ #content #text {
+ position: relative; }
+ #content #description p {
+ margin-top: .5em; }
+ #content #description h1, #content #description h2, #content #description h3, #content #description h4, #content #description h5, #content #description h6 {
+ font-family: Georgia, serif; }
+ #content #description h1 {
+ font-size: 2.2em;
+ margin-bottom: .2em;
+ border-bottom: 3px double #d8d8d8;
+ padding-bottom: .1em; }
+ #content #description h2 {
+ font-size: 1.8em;
+ color: #0e3062;
+ margin: .8em 0 .3em 0; }
+ #content #description h3 {
+ font-size: 1.6em;
+ margin: .8em 0 .3em 0;
+ color: #666666; }
+ #content #description h4 {
+ font-size: 1.4em;
+ margin: .8em 0 .3em 0; }
+ #content #description h5 {
+ font-size: 1.2em;
+ margin: .8em 0 .3em 0;
+ color: #0e3062; }
+ #content #description h6 {
+ font-size: 1.0em;
+ margin: .8em 0 .3em 0;
+ color: #666666; }
+ #content #description ul, #content #description ol, #content .method .description ul, #content .method .description ol {
+ margin: .8em 0;
+ padding-left: 1.5em; }
+ #content #description ol, #content .method .description ol {
+ list-style: decimal; }
+ #content #description ol li, #content .method .description ol li {
+ white-space: normal; }
+
+#method-list {
+ position: absolute;
+ top: 0px;
+ right: -33%;
+ width: 28%;
+ background: #eee;
+ border: 1px solid silver;
+ padding: .4em 1%;
+ overflow: hidden; }
+ #method-list h2 {
+ font-size: 1.3em; }
+ #method-list h3 {
+ font-variant: small-caps;
+ text-transform: capitalize;
+ font-family: Georgia, serif;
+ color: #666;
+ font-size: 1.1em; }
+ #method-list ol {
+ padding: 0 0 .5em .5em; }
+
+#context {
+ border-top: 1px dashed silver;
+ margin-top: 1em;
+ margin-bottom: 1em; }
+
+#context h2, #section h2 {
+ font: small-caps 1.2em Georgia, serif;
+ color: #444;
+ margin: 1em 0 .2em 0; }
+
+#methods .method {
+ border: 1px solid silver;
+ margin-top: .5em;
+ background: #eee; }
+ #methods .method .synopsis {
+ color: black;
+ background: silver;
+ padding: .2em 1em; }
+ #methods .method .synopsis .name {
+ font-weight: bold; }
+ #methods .method .synopsis a {
+ text-decoration: none; }
+ #methods .method .description {
+ padding: 0 1em; }
+ #methods .method .description pre {
+ background: #f8f8f8; }
+ #methods .method .source {
+ margin: .5em 0; }
+ #methods .method .source-toggle {
+ font-size: 85%;
+ margin-left: 1em; }
+#methods .public-class {
+ background: #ffffe4; }
+#methods .public-instance .synopsis {
+ color: #eee;
+ background: #336699; }
+
+#content .method .source pre {
+ background: #262626;
+ color: #ffdead;
+ margin: 1em;
+ padding: 0.5em;
+ border: 1px dashed #999;
+ overflow: auto; }
+ #content .method .source pre .ruby-constant {
+ color: #7fffd4;
+ background: transparent; }
+ #content .method .source pre .ruby-keyword {
+ color: #00ffff;
+ background: transparent; }
+ #content .method .source pre .ruby-ivar {
+ color: #eedd82;
+ background: transparent; }
+ #content .method .source pre .ruby-operator {
+ color: #00ffee;
+ background: transparent; }
+ #content .method .source pre .ruby-identifier {
+ color: #ffdead;
+ background: transparent; }
+ #content .method .source pre .ruby-node {
+ color: #ffa07a;
+ background: transparent; }
+ #content .method .source pre .ruby-comment {
+ color: #b22222;
+ font-weight: bold;
+ background: transparent; }
+ #content .method .source pre .ruby-regexp {
+ color: #ffa07a;
+ background: transparent; }
+ #content .method .source pre .ruby-value {
+ color: #7fffd4;
+ background: transparent; }