summaryrefslogtreecommitdiff
path: root/classes/Net/SSH/Multi/Session.html
blob: fe9cb219eefd36e9e1411d682e5ae0d5d9ea88e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
<!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</title>
    <meta content='text/html; charset=US-ASCII' http-equiv='Content-Type'>
    <link href='../../../../css/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 target="docwin" href="../../../../files/lib/net/ssh/multi/session_rb.html">lib/net/ssh/multi/session.rb</a>
          </li>
        </ol>
        <div class='parent'>
          Parent:
          <strong><a target="docwin" href="../Multi.html">Multi</a></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#method-i-group">group</a>), as well as a way to scope
            commands to a subset of all connections (<a
            href="Session.html#method-i-with">with</a>). You can also provide a default
            gateway connection that servers should use when connecting (<a
            href="Session.html#method-i-via">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;  # 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
            <a href="SessionActions.html#method-i-connect-21">connect!</a> 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'll run into open
            file handle limitations and such. If this happens to you, you can set the
            <a
            href="Session.html#attribute-i-concurrent_connections">concurrent_connections</a>
            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 <a
            href="Session.html#attribute-i-on_error">on_error</a> 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 <a
            href="Session.html#attribute-i-on_error">on_error</a>, 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;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'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#method-i-use">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#method-i-use">use</a>:</p>
            
            <pre>session.use do |opt|&#x000A;  lookup_ip_address_of_remote_host&#x000A;end</pre>
            
            <p>See <a href="Session.html#method-i-use">use</a> for more information about
            this usage.</p>
          </div>
          <div id='method-list'>
            <h2>Methods</h2>
            <h3>Public Class</h3>
            <ol>
              <li><a target="docwin" href="#method-c-new">new</a></li>
            </ol>
            <h3>Public Instance</h3>
            <ol>
              <li><a target="docwin" href="#method-i-close">close</a></li>
              <li><a target="docwin" href="#attribute-i-concurrent_connections">concurrent_connections</a></li>
              <li><a target="docwin" href="#attribute-i-default_gateway">default_gateway</a></li>
              <li><a target="docwin" href="#attribute-i-default_user">default_user</a></li>
              <li><a target="docwin" href="#method-i-group">group</a></li>
              <li><a target="docwin" href="#attribute-i-groups">groups</a></li>
              <li><a target="docwin" href="#method-i-loop">loop</a></li>
              <li><a target="docwin" href="#method-i-on">on</a></li>
              <li><a target="docwin" href="#attribute-i-on_error">on_error</a></li>
              <li><a target="docwin" href="#method-i-process">process</a></li>
              <li><a target="docwin" href="#attribute-i-server_list">server_list</a></li>
              <li><a target="docwin" href="#method-i-servers">servers</a></li>
              <li><a target="docwin" href="#method-i-servers_for">servers_for</a></li>
              <li><a target="docwin" href="#method-i-use">use</a></li>
              <li><a target="docwin" href="#method-i-via">via</a></li>
              <li><a target="docwin" href="#method-i-with">with</a></li>
            </ol>
          </div>
          <div id='context'>
            <div id='includes'>
              <h2>Included modules</h2>
              <ol>
                <li><a target="docwin" href="SessionActions.html">SessionActions</a></li>
              </ol>
            </div>
          </div>
          <div id='section'>
            <div id='aliases-list'>
              <h2>Public Instance Aliases</h2>
              <div class='name-list'>
                <table summary='Public Instance Aliases'>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>loop_forever</td>
                    <td>-&gt;</td>
                    <td class='context-item-value'><a target="docwin" href="#method-i-loop">loop</a></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'>
                      <a name='attribute-i-concurrent_connections'>concurrent_connections</a>
                    </td>
                    <td class='context-item-value'>[RW]</td>
                    <td class='context-item-desc'>
                      
                      <p>The number of allowed concurrent connections. No more than this number of
                      sessions will be open at any given time.</p>
                    </td>
                  </tr>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>
                      <a name='attribute-i-default_gateway'>default_gateway</a>
                    </td>
                    <td class='context-item-value'>[R]</td>
                    <td class='context-item-desc'>
                      
                      <p>The default Net::SSH::Gateway instance to use to connect to the servers. If
                      <tt>nil</tt>, no default gateway will be used.</p>
                    </td>
                  </tr>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>
                      <a name='attribute-i-default_user'>default_user</a>
                    </td>
                    <td class='context-item-value'>[RW]</td>
                    <td class='context-item-desc'>
                      
                      <p>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
                      <a target="_top" href="http://'USER'">ENV</a> || <a target="_top" href="http://'USERNAME'">ENV</a>, or
                      "unknown" if neither of those are set.</p>
                    </td>
                  </tr>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>
                      <a name='attribute-i-groups'>groups</a>
                    </td>
                    <td class='context-item-value'>[R]</td>
                    <td class='context-item-desc'>
                      
                      <p>The hash of group definitions, mapping each group name to a corresponding
                      <a href="ServerList.html">Net::SSH::Multi::ServerList</a>.</p>
                    </td>
                  </tr>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>
                      <a name='attribute-i-on_error'>on_error</a>
                    </td>
                    <td class='context-item-value'>[RW]</td>
                    <td class='context-item-desc'>
                      
                      <p>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.</p>
                    </td>
                  </tr>
                  <tr class='top-aligned-row context-row'>
                    <td class='context-item-name'>
                      <a name='attribute-i-server_list'>server_list</a>
                    </td>
                    <td class='context-item-value'>[R]</td>
                    <td class='context-item-desc'>
                      
                      <p>The <a href="ServerList.html">Net::SSH::Multi::ServerList</a> managed by
                      this session.</p>
                    </td>
                  </tr>
                </table>
              </div>
            </div>
            <div id='methods'>
              <h2>Public Class methods</h2>
              <div class='method public-class' id='method-method-c-new'>
                <a name='method-c-new'></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 <a
                  href="Session.html#attribute-i-concurrent_connections">concurrent_connections</a>
                  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('method-c-new-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-c-new-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 171</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">options</span>={})&#x000A;  <span class="ruby-ivar">@server_list</span> = <span class="ruby-constant">ServerList</span>.<span class="ruby-identifier">new</span>&#x000A;  <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;  <span class="ruby-ivar">@gateway</span> = <span class="ruby-keyword">nil</span>&#x000A;  <span class="ruby-ivar">@open_groups</span> = []&#x000A;  <span class="ruby-ivar">@connect_threads</span> = []&#x000A;  <span class="ruby-ivar">@on_error</span> = <span class="ruby-value">:fail</span>&#x000A;  <span class="ruby-ivar">@default_user</span> = <span class="ruby-constant">ENV</span>[<span class="ruby-string">'USER'</span>] <span class="ruby-operator">||</span> <span class="ruby-constant">ENV</span>[<span class="ruby-string">'USERNAME'</span>] <span class="ruby-operator">||</span> <span class="ruby-string">&quot;unknown&quot;</span>&#x000A;&#x000A;  <span class="ruby-ivar">@open_connections</span> = <span class="ruby-value">0</span>&#x000A;  <span class="ruby-ivar">@pending_sessions</span> = []&#x000A;  <span class="ruby-ivar">@session_mutex</span> = <span class="ruby-constant">Mutex</span>.<span class="ruby-identifier">new</span>&#x000A;&#x000A;  <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;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <h2>Public Instance methods</h2>
              <div class='method public-instance' id='method-method-i-close'>
                <a name='method-i-close'></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#method-i-via">via</a>). Note that other gateway
                  connections (e.g., those passed to <a
                  href="Session.html#method-i-use">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('method-i-close-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-close-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 402</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">close</span>&#x000A;  <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;  <span class="ruby-identifier">loop</span>(<span class="ruby-value">0</span>) { <span class="ruby-identifier">busy?</span>(<span class="ruby-keyword">true</span>) }&#x000A;  <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;  <span class="ruby-identifier">default_gateway</span>.<span class="ruby-identifier">shutdown!</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">default_gateway</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-group'>
                <a name='method-i-group'></a>
                <div class='synopsis'>
                  <span class='name'>group</span>
                  <span class='arguments'>(*args)</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 <a
                  href="Session.html#attribute-i-server_list">server_list</a> array
                  (typically by calling <a href="Session.html#method-i-use">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#method-i-use">use</a> will automatically associate the
                  new server definition with those groups. You can nest <a
                  href="Session.html#method-i-group">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('method-i-group-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-group-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 213</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">group</span>(*<span class="ruby-identifier">args</span>)&#x000A;  <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;&#x000A;  <span class="ruby-keyword">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;    <span class="ruby-identifier">raise</span> <span class="ruby-constant">ArgumentError</span>, <span class="ruby-string">&quot;must provide group mapping OR block, not both&quot;</span>&#x000A;  <span class="ruby-keyword">elsif</span> <span class="ruby-identifier">block_given?</span>&#x000A;    <span class="ruby-keyword">begin</span>&#x000A;      <span class="ruby-identifier">saved_groups</span> = <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">dup</span>&#x000A;      <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;      <span class="ruby-keyword">yield</span> <span class="ruby-keyword">self</span>&#x000A;    <span class="ruby-keyword">ensure</span>&#x000A;      <span class="ruby-identifier">open_groups</span>.<span class="ruby-identifier">replace</span>(<span class="ruby-identifier">saved_groups</span>)&#x000A;    <span class="ruby-keyword">end</span>&#x000A;  <span class="ruby-keyword">else</span>&#x000A;    <span class="ruby-identifier">mapping</span>.<span class="ruby-identifier">each</span> <span class="ruby-keyword">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;      (<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">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">grp</span><span class="ruby-operator">|</span>&#x000A;        <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;      <span class="ruby-keyword">end</span>&#x000A;    <span class="ruby-keyword">end</span>&#x000A;  <span class="ruby-keyword">end</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-loop'>
                <a name='method-i-loop'></a>
                <div class='synopsis'>
                  <span class='name'>loop</span>
                  <span class='arguments'>(wait=nil, &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 <a href="SessionActions.html#method-i-busy-3F">busy?</a> 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('method-i-loop-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-loop-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 415</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">loop</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword">nil</span>, &amp;<span class="ruby-identifier">block</span>)&#x000A;  <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;  <span class="ruby-identifier">loop_forever</span> { <span class="ruby-keyword">break</span> <span class="ruby-keyword">unless</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>, &amp;<span class="ruby-identifier">running</span>) }&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-on'>
                <a name='method-i-on'></a>
                <div class='synopsis'>
                  <span class='name'>on</span>
                  <span class='arguments'>(*servers)</span>
                </div>
                <div class='description'>
                  
                  <p>Works as <a href="Session.html#method-i-with">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#method-i-use">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('method-i-on-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-on-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 392</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">on</span>(*<span class="ruby-identifier">servers</span>)&#x000A;  <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">servers</span>)&#x000A;  <span class="ruby-keyword">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">block_given?</span>&#x000A;  <span class="ruby-identifier">subsession</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-process'>
                <a name='method-i-process'></a>
                <div class='synopsis'>
                  <span class='name'>process</span>
                  <span class='arguments'>(wait=nil, &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 "wait forever". If the block is given, then it will be used
                  to determine whether <a href="Session.html#method-i-process">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('method-i-process-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-process-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 426</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">process</span>(<span class="ruby-identifier">wait</span>=<span class="ruby-keyword">nil</span>, &amp;<span class="ruby-identifier">block</span>)&#x000A;  <span class="ruby-identifier">realize_pending_connections!</span>&#x000A;  <span class="ruby-identifier">wait</span> = <span class="ruby-ivar">@connect_threads</span>.<span class="ruby-identifier">any?</span> <span class="ruby-operator">?</span> <span class="ruby-value">0</span> <span class="ruby-operator">:</span> <span class="ruby-identifier">wait</span>&#x000A;&#x000A;  <span class="ruby-keyword">return</span> <span class="ruby-keyword">false</span> <span class="ruby-keyword">unless</span> <span class="ruby-identifier">preprocess</span>(&amp;<span class="ruby-identifier">block</span>)&#x000A;&#x000A;  <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;  <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;&#x000A;  <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">nil</span>, <span class="ruby-identifier">wait</span>)&#x000A;&#x000A;  <span class="ruby-keyword">if</span> <span class="ruby-identifier">readers</span>&#x000A;    <span class="ruby-keyword">return</span> <span class="ruby-identifier">postprocess</span>(<span class="ruby-identifier">readers</span>, <span class="ruby-identifier">writers</span>)&#x000A;  <span class="ruby-keyword">else</span>&#x000A;    <span class="ruby-keyword">return</span> <span class="ruby-keyword">true</span>&#x000A;  <span class="ruby-keyword">end</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-servers'>
                <a name='method-i-servers'></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#method-i-servers_for">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('method-i-servers-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-servers-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 293</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">servers</span>&#x000A;  <span class="ruby-identifier">servers_for</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-servers_for'>
                <a name='method-i-servers_for'></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 "only"
                  constraints (which restrict the set of servers to "only" those that match
                  the given properties) or "except" 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;# 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('method-i-servers_for-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-servers_for-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 334</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">servers_for</span>(*<span class="ruby-identifier">criteria</span>)&#x000A;  <span class="ruby-keyword">if</span> <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">empty?</span>&#x000A;    <span class="ruby-identifier">server_list</span>.<span class="ruby-identifier">flatten</span>&#x000A;  <span class="ruby-keyword">else</span>&#x000A;    <span class="ruby-comment"># normalize the criteria list, so that every entry is a key to a</span>&#x000A;    <span class="ruby-comment"># criteria hash (possibly empty).</span>&#x000A;    <span class="ruby-identifier">criteria</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>({}) <span class="ruby-keyword">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;      <span class="ruby-keyword">case</span> <span class="ruby-identifier">entry</span>&#x000A;      <span class="ruby-keyword">when</span> <span class="ruby-constant">Hash</span> <span class="ruby-keyword">then</span> <span class="ruby-identifier">hash</span>.<span class="ruby-identifier">merge</span>(<span class="ruby-identifier">entry</span>)&#x000A;      <span class="ruby-keyword">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;      <span class="ruby-keyword">end</span>&#x000A;    <span class="ruby-keyword">end</span>&#x000A;&#x000A;    <span class="ruby-identifier">list</span> = <span class="ruby-identifier">criteria</span>.<span class="ruby-identifier">inject</span>([]) <span class="ruby-keyword">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;      <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">unless</span> <span class="ruby-identifier">properties</span>.<span class="ruby-identifier">is_a?</span>(<span class="ruby-constant">Hash</span>)&#x000A;      <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-value">:only</span>, <span class="ruby-value">:except</span>]&#x000A;      <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">unless</span> <span class="ruby-identifier">bad_keys</span>.<span class="ruby-identifier">empty?</span>&#x000A;&#x000A;      <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">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">server</span><span class="ruby-operator">|</span>&#x000A;        (<span class="ruby-identifier">properties</span>[<span class="ruby-value">: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;        <span class="ruby-operator">!</span>(<span class="ruby-identifier">properties</span>[<span class="ruby-value">: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;      <span class="ruby-keyword">end</span>&#x000A;&#x000A;      <span class="ruby-identifier">aggregator</span>.<span class="ruby-identifier">concat</span>(<span class="ruby-identifier">servers</span>)&#x000A;    <span class="ruby-keyword">end</span>&#x000A;&#x000A;    <span class="ruby-identifier">list</span>.<span class="ruby-identifier">uniq</span>&#x000A;  <span class="ruby-keyword">end</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-use'>
                <a name='method-i-use'></a>
                <div class='synopsis'>
                  <span class='name'>use</span>
                  <span class='arguments'>(*hosts, &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#method-i-via">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#method-i-use">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('method-i-use-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-use-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 274</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">use</span>(*<span class="ruby-identifier">hosts</span>, &amp;<span class="ruby-identifier">block</span>)&#x000A;  <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;  <span class="ruby-identifier">options</span> = { <span class="ruby-value">: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;&#x000A;  <span class="ruby-identifier">results</span> = <span class="ruby-identifier">hosts</span>.<span class="ruby-identifier">map</span> <span class="ruby-keyword">do</span> <span class="ruby-operator">|</span><span class="ruby-identifier">host</span><span class="ruby-operator">|</span>&#x000A;    <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">self</span>, <span class="ruby-identifier">host</span>, <span class="ruby-identifier">options</span>))&#x000A;  <span class="ruby-keyword">end</span>&#x000A;&#x000A;  <span class="ruby-keyword">if</span> <span class="ruby-identifier">block</span>&#x000A;    <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">self</span>, <span class="ruby-identifier">options</span>, <span class="ruby-identifier">block</span>))&#x000A;  <span class="ruby-keyword">end</span>&#x000A;&#x000A;  <span class="ruby-identifier">group</span> [] =<span class="ruby-operator">&gt;</span> <span class="ruby-identifier">results</span>&#x000A;  <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;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-via'>
                <a name='method-i-via'></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#method-i-use">use</a> method; see <a
                  href="Session.html#method-i-use">use</a> for details.</p>
                </div>
                <div class='source'>
                  <a class='source-toggle' href='#' onclick="toggleCode('method-i-via-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-via-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 243</span>&#x000A;<span class="ruby-keyword">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;  <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;  <span class="ruby-keyword">self</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
              <div class='method public-instance' id='method-method-i-with'>
                <a name='method-i-with'></a>
                <div class='synopsis'>
                  <span class='name'>with</span>
                  <span class='arguments'>(*groups)</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#method-i-servers_for">servers_for</a> for a discussion
                  of how these criteria are interpreted.</p>
                  
                  <pre>session.with(:app).exec('hostname')&#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('method-i-with-source'); return false">
                    [show source]
                  </a>
                  <pre id='method-i-with-source'><span class="ruby-comment"># File lib/net/ssh/multi/session.rb, line 375</span>&#x000A;<span class="ruby-keyword">def</span> <span class="ruby-identifier">with</span>(*<span class="ruby-identifier">groups</span>)&#x000A;  <span class="ruby-identifier">subsession</span> = <span class="ruby-constant">Subsession</span>.<span class="ruby-identifier">new</span>(<span class="ruby-keyword">self</span>, <span class="ruby-identifier">servers_for</span>(*<span class="ruby-identifier">groups</span>))&#x000A;  <span class="ruby-keyword">yield</span> <span class="ruby-identifier">subsession</span> <span class="ruby-keyword">if</span> <span class="ruby-identifier">block_given?</span>&#x000A;  <span class="ruby-identifier">subsession</span>&#x000A;<span class="ruby-keyword">end</span></pre>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div id='footer-push'></div>
    </div>
    <div id='footer'>
      <a target="docwin" href="http://github.com/mislav/hanna/tree/master"><strong>Hanna</strong> RDoc template</a>
    </div>
  </body>
</html>