resque-pool-dynamic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <base id="base_target" target="_parent" />
19
+ </head>
20
+ <body>
21
+ <script type="text/javascript" charset="utf-8">
22
+ if (window.top.frames.main) {
23
+ document.getElementById('base_target').target = 'main';
24
+ document.body.className = 'frames';
25
+ }
26
+ </script>
27
+ <div id="content">
28
+ <h1 id="full_list_header">File List</h1>
29
+ <div id="nav">
30
+
31
+ <a target="_self" href="class_list.html">Classes</a>
32
+
33
+ <a target="_self" href="method_list.html">Methods</a>
34
+
35
+ <a target="_self" href="file_list.html">Files</a>
36
+
37
+ </div>
38
+ <div id="search">Search: <input type="text" /></div>
39
+
40
+ <ul id="full_list" class="files">
41
+
42
+
43
+ <li class="r1"><a href="index.html" title="README">README</a></li>
44
+
45
+
46
+ </ul>
47
+ </div>
48
+ </body>
49
+ </html>
data/doc/frames.html ADDED
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+ <title>Documentation by YARD 0.7.5</title>
8
+ </head>
9
+ <frameset cols="20%,*">
10
+ <frame name="list" src="class_list.html" />
11
+ <frame name="main" src="index.html" />
12
+ </frameset>
13
+ </html>
data/doc/index.html ADDED
@@ -0,0 +1,316 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.7.5
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ relpath = '';
19
+ if (relpath != '') relpath += '/';
20
+ </script>
21
+
22
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
25
+
26
+
27
+ </head>
28
+ <body>
29
+ <script type="text/javascript" charset="utf-8">
30
+ if (window.top.frames.main) document.body.className = 'frames';
31
+ </script>
32
+
33
+ <div id="header">
34
+ <div id="menu">
35
+
36
+ <a href="_index.html" title="Index">Index</a> &raquo;
37
+ <span class="title">File: README</span>
38
+
39
+
40
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
+ </div>
42
+
43
+ <div id="search">
44
+
45
+ <a id="class_list_link" href="#">Class List</a>
46
+
47
+ <a id="method_list_link" href="#">Method List</a>
48
+
49
+ <a id="file_list_link" href="#">File List</a>
50
+
51
+ </div>
52
+ <div class="clear"></div>
53
+ </div>
54
+
55
+ <iframe id="search_frame"></iframe>
56
+
57
+ <div id="content"><div id='filecontents'><h1 id="dynamic-resque-pool">Dynamic Resque Pool</h1>
58
+
59
+ <p><a href="https://github.com/nevans/resque-pool">Resque pool</a> by Nicholas Evans
60
+ is a library for managing a pool of
61
+ <a href="http://github.com/defunkt/resque">resque</a> workers. Given a a config
62
+ file, it manages your workers for you, starting up the appropriate
63
+ number of workers for each worker type.</p>
64
+
65
+ <p>While the resque pool is convenient for a permanent process
66
+ overlooking a fairly constant set of workers, it is less than
67
+ convenient to use for more dynamic tasks - one-time long running batch
68
+ processing worker families that need to be started and supervised
69
+ manually, and often require adjusting number of worker processes for
70
+ maximum performance.</p>
71
+
72
+ <p>Workflow for this kind of task would be:</p>
73
+
74
+ <ul>
75
+ <li>prepare a yaml file with number of workers</li>
76
+ <li>start resque-pool</li>
77
+ <li><code>tail -f</code> the log file on the other console</li>
78
+ <li>look into <code>pstree</code> (or <code>ps faxuw</code> on Linux)</li>
79
+ <li>babysit the process, check the system load whether number of workers
80
+ needs to be adjusted</li>
81
+ <li>edit the yaml file</li>
82
+ <li><code>kill -HUP</code> the resque pool master (hope you remembered the PID from
83
+ pstree!)</li>
84
+ <li>rinse, repeat</li>
85
+ </ul>
86
+
87
+ <p>Or you can add <code>gem "resque-pool-dynamic"</code> to your Gemfile, <code>require
88
+ 'resque/pool/dynamic/tasks'</code> to your Rakefile, and start an
89
+ interactive CLI interface that controls the resque-pool-master.</p>
90
+
91
+ <h2 id="example-resque-pool-manager-session">Example resque-pool-manager session</h2>
92
+
93
+ <pre class="code ruby"><code>$ bundle exec rake resque:pool:dynamic WORKERS=foo=2:bar=2:\*=1
94
+ resque-pool-manager[21134]: started manager
95
+
96
+ Status: running, pid: 21134
97
+ Configuration:
98
+ bar: 2
99
+ &quot;*&quot;: 1
100
+ foo: 2
101
+ Process tree:
102
+ -+= 21134 japhy resque-pool-master: managing [21136, 21135, 21137, 21138, 21141]
103
+ |--- 21135 japhy resque-1.20.0: Waiting for bar
104
+ |--- 21136 japhy resque-1.20.0: Waiting for bar
105
+ |--- 21137 japhy resque-1.20.0: Waiting for *
106
+ |--- 21138 japhy resque-1.20.0: Waiting for foo
107
+ \--- 21141 japhy resque-1.20.0: Waiting for foo
108
+
109
+ &gt;&gt; log.tail
110
+ resque-pool-manager[21134]: Pool contains worker PIDs: [21136, 21135, 21137, 21138, 21141]
111
+ resque-pool-worker[21135]: Starting worker portinari.local:21135:bar
112
+ resque-pool-worker[21137]: Starting worker portinari.local:21137:*
113
+
114
+ resque-pool-worker[21136]: Starting worker portinari.local:21136:bar
115
+ resque-pool-worker[21141]: Starting worker portinari.local:21141:foo
116
+ resque-pool-worker[21138]: Starting worker portinari.local:21138:foo
117
+ </code></pre>
118
+
119
+ <p>(log.tail is following the logfile like <code>tail -f</code> until you break with ^C)</p>
120
+
121
+ <pre class="code ruby"><code>^C&gt;&gt; config :foo =&gt; 1, :bar =&gt; 4
122
+ Reloading resque-pool-master 21134 configuration
123
+ =&gt; {&quot;bar&quot;=&gt;4, &quot;*&quot;=&gt;1, &quot;foo&quot;=&gt;1}
124
+ &gt;&gt; status
125
+
126
+ Status: running, pid: 21134
127
+ Configuration:
128
+ bar: 4
129
+ &quot;*&quot;: 1
130
+ foo: 1
131
+ Process tree:
132
+ -+= 21134 japhy resque-pool-master: managing [21176, 21178, 21162, 21163, 21180, 21181]
133
+ |--- 21162 japhy resque-1.20.0: Waiting for bar
134
+ |--- 21163 japhy resque-1.20.0: Waiting for bar
135
+ |--- 21176 japhy resque-1.20.0: Waiting for bar
136
+ |--- 21178 japhy resque-1.20.0: Waiting for bar
137
+ |--- 21180 japhy resque-1.20.0: Waiting for *
138
+ \--- 21181 japhy resque-1.20.0: Waiting for foo
139
+
140
+ &gt;&gt; log.tail
141
+ resque-pool-manager[21134]: HUP: reload config file and reload logfiles
142
+ resque-pool-manager[21134]: Flushing logs
143
+ resque-pool-manager[21134]: HUP: gracefully shutdown old children (which have old logfiles open)
144
+ resque-pool-manager[21134]: HUP: new children will inherit new logfiles
145
+ resque-pool-worker[21163]: Starting worker portinari.local:21163:bar
146
+ resque-pool-worker[21162]: Starting worker portinari.local:21162:bar
147
+ resque-pool-manager[21134]: Reaped resque worker[21136] (status: 0) queues: bar
148
+ resque-pool-manager[21134]: Reaped resque worker[21135] (status: 0) queues: bar
149
+ resque-pool-worker[21176]: Starting worker portinari.local:21176:bar
150
+ resque-pool-worker[21178]: Starting worker portinari.local:21178:bar
151
+ resque-pool-manager[21134]: Reaped resque worker[21141] (status: 0) queues: foo
152
+ resque-pool-manager[21134]: Reaped resque worker[21138] (status: 0) queues: foo
153
+ resque-pool-worker[21180]: Starting worker portinari.local:21180:*
154
+ resque-pool-worker[21181]: Starting worker portinari.local:21181:foo
155
+ ^C&gt;&gt; exit
156
+ Bye!
157
+ Shutting down resque-pool-master 21134
158
+ resque-pool-manager[21134]: INT: immediate shutdown (graceful worker shutdown)
159
+ resque-pool-manager[21134]: manager finished
160
+ $ _
161
+ </code></pre>
162
+
163
+ <h2 id="command-line-interface">Command Line Interface</h2>
164
+
165
+ <p>The CLI is a slightly customized Ripl shell (an IRB replacement)
166
+ started in context of a <code>Resque::Pool::Dynamic</code> instance. You can use
167
+ all Ruby you want, and call all the methods for controlling the resque
168
+ pool. A simple built-in help for the custom methods is included:</p>
169
+
170
+ <pre class="code ruby"><code>&gt;&gt; help
171
+ Known commands:
172
+ config - &quot;WORKERS&quot;, as interpreted by the #parse_config_string method.
173
+ config_path - Path to the temporary config file.
174
+ exit - Finish work
175
+ has_log? - True if we have an open log file.
176
+ kill! - Send signal to a running resque-pool.
177
+ log - Open log of resque-pool process.
178
+ log.ff - Fast forward until end of file (see IO::Tail#backward).
179
+ log.rew - Rewind until beginning of file (see IO::Tail#forward).
180
+ log.rewind - Rewind until beginning of file (see IO::Tail#forward).
181
+ log.tail - Show last n lines of the file, or follow the file.
182
+ log.tail_to_eof - Print contents of the file until current end of file.
183
+ log.tail_until - Follow the file until a line matches regexp.
184
+ log_path - Logfile path.
185
+ pid - PID of the resque-pool process, or nil if it's not running.
186
+ pstree - Show child process tree by calling `pstree` system command.
187
+ reload - Reload resque-pool configuration.
188
+ start - Start resque-pool, showing startup logs.
189
+ start! - Fork a child process for resque-pool master.
190
+ status - Show current status.
191
+ stop - Stop running resque-pool, show shutdown logs.
192
+ stop! - Stop running resque-pool.
193
+ write_config - Write temporary configuration file.
194
+ For details, type: help command
195
+ &gt;&gt; help config
196
+ -------------------------------- Method: #config (Resque::Pool::Dynamic)
197
+ (Defined in: lib/resque/pool/dynamic/process.rb)
198
+ dynamic.config -&gt; Hash
199
+ dynamic.config(opts) -&gt; Hash
200
+ ------------------------------------------------------------------------
201
+ Note: Default configuration is taken from environment variable
202
+ &quot;WORKERS&quot;, as interpreted by the #parse_config_string method.
203
+ Examples:
204
+ ---------
205
+ # config
206
+ #=&gt; {&quot;foo&quot;=&gt;1, &quot;bar&quot;=&gt;2}
207
+ config :foo =&gt; 2, :baz =&gt; 7
208
+ #=&gt; {&quot;foo&quot;=&gt;2, &quot;baz&quot;=&gt;7, &quot;bar&quot;=&gt;2}
209
+ config :bar =&gt; 0
210
+ #=&gt; {&quot;foo&quot;=&gt;2, &quot;baz&quot;=&gt;7}
211
+ Overloads:
212
+ ----------
213
+ ------------------------------------------------------------------------
214
+ dynamic.config -&gt; Hash
215
+ ------------------------------------------------------------------------
216
+ Show current workers configuration
217
+ Returns:
218
+ --------
219
+ (Hash) -
220
+ ------------------------------------------------------------------------
221
+ dynamic.config(opts) -&gt; Hash
222
+ ------------------------------------------------------------------------
223
+ Update workers configuration. If configuration has change and
224
+ resque-pool is running, it is reloaded.
225
+ Parameters:
226
+ -----------
227
+ (Hash) opts - Dictionary of worker process counts to update
228
+ (pass 0 or nil as value to delete all workers for a queue from pool)
229
+ Returns:
230
+ --------
231
+ (Hash) - Updated config
232
+ &gt;&gt; _
233
+ </code></pre>
234
+
235
+ <p>The built-in help is autogenerated from Yard documentation on methods;
236
+ if you’re curious, look into the Rakefile for details.</p>
237
+
238
+ <h2 id="rake-task-documentation">Rake task documentation</h2>
239
+
240
+ <pre class="code ruby"><code>$ bundle exec rake -D resque:pool:dynamic
241
+ rake resque:pool:dynamic
242
+ Starts a dynamic pool of Resque worker processes.
243
+
244
+ Variables:
245
+ WORKERS=worker spec - specify initial numbers of workers
246
+ (look below for format description)
247
+ NO_START=1 - don't start resque-pool master automatically
248
+ (default is to start)
249
+
250
+ Workers spec format:
251
+ queue_name=process_number[:queue_name=process_number[:...]]
252
+
253
+ queue_name can be whatever resque:work will accept as QUEUE=
254
+ parameter.
255
+
256
+ Example:
257
+ $ rake resque:pool:dynamic WORKERS=foo=1:bar=1:baz,quux,xyzzy=5:*=2
258
+ will start:
259
+ - one worker for queue 'foo'
260
+ - one worker for queue 'bar'
261
+ - five workers for queues baz,quux,xyzzy
262
+ - two workers for all queues
263
+ </code></pre>
264
+
265
+ <h2 id="api-and-code-structure">API and code structure</h2>
266
+
267
+ <p>The Rake task, defined in <code>resque/pool/dynamic/tasks.rb</code>, is a
268
+ one-liner calling out to <code>Resque::Pool::Dynamic.shell</code>, which starts
269
+ the command line interface.</p>
270
+
271
+ <p>The CLI itself, defined in <code>resque/pool/dynamic/shell.rb</code>, is a thin
272
+ layer (8 lines of code + Ripl UI tweaks) over an instance of the
273
+ <code>Resque::Pool::Dynamic</code> class.</p>
274
+
275
+ <p>The workhorse <code>Resque::Pool::Dynamic</code> class is defined in
276
+ <code>resque/pool/dynamic.rb</code>. It can be easily instantiated in the code
277
+ independent from the CLI; the CLI commands are just instance methods
278
+ you can call then.</p>
279
+
280
+ <h3 id="ideas">Ideas</h3>
281
+
282
+ <p>Besides interactive, supervised work, <code>Resque::Pool::Dynamic</code> can be
283
+ used separately from the UI for dynamic, reactive management of
284
+ workers, implementing some kind of autoscaling and load distribution
285
+ logic.</p>
286
+
287
+ <p>It can be used during load tests to automatically optimize best number
288
+ of workers for maximum processing speed, while keeping load average
289
+ and memory or CPU usage goals.</p>
290
+
291
+ <p>It may also react to queue depths, e.g. temporarily reallocating idle
292
+ workers to overloaded queues or shutting them down to conserve memory,
293
+ or actively managing sudden short peak usage by stopping other workers
294
+ and switching them to peaking queue.</p>
295
+
296
+ <p>It may also simply allocate workers dynamically based on time of day,
297
+ to e.g. have more workers performing UI-related task in the day, which
298
+ increases perceived responsiveness, and switch them to process
299
+ long-running reports overnight when there are less users.</p>
300
+
301
+ <h2 id="detailed-documentation-and-source-code">Detailed documentation and source code</h2>
302
+
303
+ <ul>
304
+ <li>http://rubydoc.info/FIXME</li>
305
+ <li>http://github.com/mpasternacki/resque-pool-dynamic</li>
306
+ </ul>
307
+ </div></div>
308
+
309
+ <div id="footer">
310
+ Generated on Wed Apr 25 21:03:02 2012 by
311
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
312
+ 0.7.5 (ruby-1.9.2).
313
+ </div>
314
+
315
+ </body>
316
+ </html>
data/doc/js/app.js ADDED
@@ -0,0 +1,205 @@
1
+ function createSourceLinks() {
2
+ $('.method_details_list .source_code').
3
+ before("<span class='showSource'>[<a href='#' class='toggleSource'>View source</a>]</span>");
4
+ $('.toggleSource').toggle(function() {
5
+ $(this).parent().nextAll('.source_code').slideDown(100);
6
+ $(this).text("Hide source");
7
+ },
8
+ function() {
9
+ $(this).parent().nextAll('.source_code').slideUp(100);
10
+ $(this).text("View source");
11
+ });
12
+ }
13
+
14
+ function createDefineLinks() {
15
+ var tHeight = 0;
16
+ $('.defines').after(" <a href='#' class='toggleDefines'>more...</a>");
17
+ $('.toggleDefines').toggle(function() {
18
+ tHeight = $(this).parent().prev().height();
19
+ $(this).prev().show();
20
+ $(this).parent().prev().height($(this).parent().height());
21
+ $(this).text("(less)");
22
+ },
23
+ function() {
24
+ $(this).prev().hide();
25
+ $(this).parent().prev().height(tHeight);
26
+ $(this).text("more...");
27
+ });
28
+ }
29
+
30
+ function createFullTreeLinks() {
31
+ var tHeight = 0;
32
+ $('.inheritanceTree').toggle(function() {
33
+ tHeight = $(this).parent().prev().height();
34
+ $(this).parent().toggleClass('showAll');
35
+ $(this).text("(hide)");
36
+ $(this).parent().prev().height($(this).parent().height());
37
+ },
38
+ function() {
39
+ $(this).parent().toggleClass('showAll');
40
+ $(this).parent().prev().height(tHeight);
41
+ $(this).text("show all");
42
+ });
43
+ }
44
+
45
+ function fixBoxInfoHeights() {
46
+ $('dl.box dd.r1, dl.box dd.r2').each(function() {
47
+ $(this).prev().height($(this).height());
48
+ });
49
+ }
50
+
51
+ function searchFrameLinks() {
52
+ $('#method_list_link').click(function() {
53
+ toggleSearchFrame(this, relpath + 'method_list.html');
54
+ });
55
+
56
+ $('#class_list_link').click(function() {
57
+ toggleSearchFrame(this, relpath + 'class_list.html');
58
+ });
59
+
60
+ $('#file_list_link').click(function() {
61
+ toggleSearchFrame(this, relpath + 'file_list.html');
62
+ });
63
+ }
64
+
65
+ function toggleSearchFrame(id, link) {
66
+ var frame = $('#search_frame');
67
+ $('#search a').removeClass('active').addClass('inactive');
68
+ if (frame.attr('src') == link && frame.css('display') != "none") {
69
+ frame.slideUp(100);
70
+ $('#search a').removeClass('active inactive');
71
+ }
72
+ else {
73
+ $(id).addClass('active').removeClass('inactive');
74
+ frame.attr('src', link).slideDown(100);
75
+ }
76
+ }
77
+
78
+ function linkSummaries() {
79
+ $('.summary_signature').click(function() {
80
+ document.location = $(this).find('a').attr('href');
81
+ });
82
+ }
83
+
84
+ function framesInit() {
85
+ if (window.top.frames.main) {
86
+ document.body.className = 'frames';
87
+ $('#menu .noframes a').attr('href', document.location);
88
+ $('html head title', window.parent.document).text($('html head title').text());
89
+ }
90
+ }
91
+
92
+ function keyboardShortcuts() {
93
+ if (window.top.frames.main) return;
94
+ $(document).keypress(function(evt) {
95
+ if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) return;
96
+ if (typeof evt.target !== "undefined" &&
97
+ (evt.target.nodeName == "INPUT" ||
98
+ evt.target.nodeName == "TEXTAREA")) return;
99
+ switch (evt.charCode) {
100
+ case 67: case 99: $('#class_list_link').click(); break; // 'c'
101
+ case 77: case 109: $('#method_list_link').click(); break; // 'm'
102
+ case 70: case 102: $('#file_list_link').click(); break; // 'f'
103
+ default: break;
104
+ }
105
+ });
106
+ }
107
+
108
+ function summaryToggle() {
109
+ $('.summary_toggle').click(function() {
110
+ localStorage.summaryCollapsed = $(this).text();
111
+ $(this).text($(this).text() == "collapse" ? "expand" : "collapse");
112
+ var next = $(this).parent().parent().nextAll('ul.summary').first();
113
+ if (next.hasClass('compact')) {
114
+ next.toggle();
115
+ next.nextAll('ul.summary').first().toggle();
116
+ }
117
+ else if (next.hasClass('summary')) {
118
+ var list = $('<ul class="summary compact" />');
119
+ list.html(next.html());
120
+ list.find('.summary_desc, .note').remove();
121
+ list.find('a').each(function() {
122
+ $(this).html($(this).find('strong').html());
123
+ $(this).parent().html($(this)[0].outerHTML);
124
+ });
125
+ next.before(list);
126
+ next.toggle();
127
+ }
128
+ return false;
129
+ });
130
+ if (localStorage) {
131
+ if (localStorage.summaryCollapsed == "collapse") $('.summary_toggle').click();
132
+ else localStorage.summaryCollapsed = "expand";
133
+ }
134
+ }
135
+
136
+ function fixOutsideWorldLinks() {
137
+ $('a').each(function() {
138
+ if (window.location.host != this.host) this.target = '_parent';
139
+ });
140
+ }
141
+
142
+ function generateTOC() {
143
+ if ($('#filecontents').length === 0) return;
144
+ var _toc = $('<ol class="top"></ol>');
145
+ var show = false;
146
+ var toc = _toc;
147
+ var counter = 0;
148
+ var tags = ['h2', 'h3', 'h4', 'h5', 'h6'];
149
+ var i;
150
+ if ($('#filecontents h1').length > 1) tags.unshift('h1');
151
+ for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; }
152
+ var lastTag = parseInt(tags[0][1], 10);
153
+ $(tags.join(', ')).each(function() {
154
+ if (this.id == "filecontents") return;
155
+ show = true;
156
+ var thisTag = parseInt(this.tagName[1], 10);
157
+ if (this.id.length === 0) {
158
+ var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_');
159
+ if ($('#' + proposedId).length > 0) { proposedId += counter; counter++; }
160
+ this.id = proposedId;
161
+ }
162
+ if (thisTag > lastTag) {
163
+ for (i = 0; i < thisTag - lastTag; i++) {
164
+ var tmp = $('<ol/>'); toc.append(tmp); toc = tmp;
165
+ }
166
+ }
167
+ if (thisTag < lastTag) {
168
+ for (i = 0; i < lastTag - thisTag; i++) toc = toc.parent();
169
+ }
170
+ toc.append('<li><a href="#' + this.id + '">' + $(this).text() + '</a></li>');
171
+ lastTag = thisTag;
172
+ });
173
+ if (!show) return;
174
+ html = '<div id="toc"><p class="title"><a class="hide_toc" href="#"><strong>Table of Contents</strong></a> <small>(<a href="#" class="float_toc">left</a>)</small></p></div>';
175
+ $('#content').prepend(html);
176
+ $('#toc').append(_toc);
177
+ $('#toc .hide_toc').toggle(function() {
178
+ $('#toc .top').slideUp('fast');
179
+ $('#toc').toggleClass('hidden');
180
+ $('#toc .title small').toggle();
181
+ }, function() {
182
+ $('#toc .top').slideDown('fast');
183
+ $('#toc').toggleClass('hidden');
184
+ $('#toc .title small').toggle();
185
+ });
186
+ $('#toc .float_toc').toggle(function() {
187
+ $(this).text('float');
188
+ $('#toc').toggleClass('nofloat');
189
+ }, function() {
190
+ $(this).text('left');
191
+ $('#toc').toggleClass('nofloat');
192
+ });
193
+ }
194
+
195
+ $(framesInit);
196
+ $(createSourceLinks);
197
+ $(createDefineLinks);
198
+ $(createFullTreeLinks);
199
+ $(fixBoxInfoHeights);
200
+ $(searchFrameLinks);
201
+ $(linkSummaries);
202
+ $(keyboardShortcuts);
203
+ $(summaryToggle);
204
+ $(fixOutsideWorldLinks);
205
+ $(generateTOC);