summaryrefslogtreecommitdiff
path: root/code/spyglass/docs
diff options
context:
space:
mode:
Diffstat (limited to 'code/spyglass/docs')
-rw-r--r--code/spyglass/docs/configurator.html137
-rw-r--r--code/spyglass/docs/docco.css500
-rw-r--r--code/spyglass/docs/logging.html105
-rw-r--r--code/spyglass/docs/lookout.html325
-rw-r--r--code/spyglass/docs/master.html268
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-bold.eotbin0 -> 29804 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-bold.ttfbin0 -> 66836 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-bold.woffbin0 -> 33244 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-light.eotbin0 -> 29509 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-light.ttfbin0 -> 68620 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/aller-light.woffbin0 -> 33124 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/novecento-bold.eotbin0 -> 18190 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/novecento-bold.ttfbin0 -> 48136 bytes
-rwxr-xr-xcode/spyglass/docs/public/fonts/novecento-bold.woffbin0 -> 20576 bytes
-rw-r--r--code/spyglass/docs/public/stylesheets/normalize.css375
-rw-r--r--code/spyglass/docs/server.html109
-rw-r--r--code/spyglass/docs/spyglass.html106
-rw-r--r--code/spyglass/docs/worker.html305
18 files changed, 2230 insertions, 0 deletions
diff --git a/code/spyglass/docs/configurator.html b/code/spyglass/docs/configurator.html
new file mode 100644
index 0000000..69c19a5
--- /dev/null
+++ b/code/spyglass/docs/configurator.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>configurator.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>configurator.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="class"><span class="keyword">class</span> <span class="title">Configurator</span></span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <p>A hash of key =&gt; default</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="constant">OPTIONS</span> = {
+ <span class="symbol">:port</span> =&gt; <span class="number">4222</span>,
+ <span class="symbol">:host</span> =&gt; <span class="string">'0.0.0.0'</span>,
+ <span class="symbol">:workers</span> =&gt; <span class="number">2</span>,
+ <span class="symbol">:timeout</span> =&gt; <span class="number">30</span>,
+ <span class="symbol">:config_ru_path</span> =&gt; <span class="string">'config.ru'</span>,
+ <span class="symbol">:verbose</span> =&gt; <span class="keyword">false</span>,
+ <span class="symbol">:vverbose</span> =&gt; <span class="keyword">false</span>
+ }
+
+ <span class="class"><span class="keyword">class</span> <span class="inheritance">&lt;</span><span class="inheritance">&lt; <span class="parent">self</span></span></span>
+ <span class="constant">OPTIONS</span>.each <span class="keyword">do</span> |key, default|</pre></div></div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+ <p>attr_writer key</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre>
+ define_method(key) <span class="keyword">do</span> |*args|
+ arg = args.shift
+ <span class="keyword">if</span> arg
+ instance_variable_set(<span class="string">"@<span class="subst">#{key}</span>"</span>, arg)
+ <span class="keyword">else</span>
+ instance_variable_get(<span class="string">"@<span class="subst">#{key}</span>"</span>) || default
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="constant">Config</span> = <span class="constant">Configurator</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/docco.css b/code/spyglass/docs/docco.css
new file mode 100644
index 0000000..f690a07
--- /dev/null
+++ b/code/spyglass/docs/docco.css
@@ -0,0 +1,500 @@
+/*--------------------- Typography ----------------------------*/
+
+@font-face {
+ font-family: 'aller-light';
+ src: url('public/fonts/aller-light.eot');
+ src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
+ url('public/fonts/aller-light.woff') format('woff'),
+ url('public/fonts/aller-light.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'aller-bold';
+ src: url('public/fonts/aller-bold.eot');
+ src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
+ url('public/fonts/aller-bold.woff') format('woff'),
+ url('public/fonts/aller-bold.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'novecento-bold';
+ src: url('public/fonts/novecento-bold.eot');
+ src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
+ url('public/fonts/novecento-bold.woff') format('woff'),
+ url('public/fonts/novecento-bold.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
+
+/*--------------------- Layout ----------------------------*/
+html { height: 100%; }
+body {
+ font-family: "aller-light";
+ font-size: 14px;
+ line-height: 18px;
+ color: #30404f;
+ margin: 0; padding: 0;
+ height:100%;
+}
+#container { min-height: 100%; }
+
+a {
+ color: #000;
+}
+
+b, strong {
+ font-weight: normal;
+ font-family: "aller-bold";
+}
+
+p, ul, ol {
+ margin: 15px 0 0px;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #112233;
+ line-height: 1em;
+ font-weight: normal;
+ font-family: "novecento-bold";
+ text-transform: uppercase;
+ margin: 30px 0 15px 0;
+}
+
+h1 {
+ margin-top: 40px;
+}
+
+hr {
+ border: 0;
+ background: 1px solid #ddd;
+ height: 1px;
+ margin: 20px 0;
+}
+
+pre, tt, code {
+ font-size: 12px; line-height: 16px;
+ font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
+ margin: 0; padding: 0;
+}
+ .annotation pre {
+ display: block;
+ margin: 0;
+ padding: 7px 10px;
+ background: #fcfcfc;
+ -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
+ -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
+ overflow-x: auto;
+ }
+ .annotation pre code {
+ border: 0;
+ padding: 0;
+ background: transparent;
+ }
+
+
+blockquote {
+ border-left: 5px solid #ccc;
+ margin: 0;
+ padding: 1px 0 1px 1em;
+}
+ .sections blockquote p {
+ font-family: Menlo, Consolas, Monaco, monospace;
+ font-size: 12px; line-height: 16px;
+ color: #999;
+ margin: 10px 0 0;
+ white-space: pre-wrap;
+ }
+
+ul.sections {
+ list-style: none;
+ padding:0 0 5px 0;;
+ margin:0;
+}
+
+/*
+ Force border-box so that % widths fit the parent
+ container without overlap because of margin/padding.
+
+ More Info : http://www.quirksmode.org/css/box.html
+*/
+ul.sections > li > div {
+ -moz-box-sizing: border-box; /* firefox */
+ -ms-box-sizing: border-box; /* ie */
+ -webkit-box-sizing: border-box; /* webkit */
+ -khtml-box-sizing: border-box; /* konqueror */
+ box-sizing: border-box; /* css3 */
+}
+
+
+/*---------------------- Jump Page -----------------------------*/
+#jump_to, #jump_page {
+ margin: 0;
+ background: white;
+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
+ font: 16px Arial;
+ cursor: pointer;
+ text-align: right;
+ list-style: none;
+}
+
+#jump_to a {
+ text-decoration: none;
+}
+
+#jump_to a.large {
+ display: none;
+}
+#jump_to a.small {
+ font-size: 22px;
+ font-weight: bold;
+ color: #676767;
+}
+
+#jump_to, #jump_wrapper {
+ position: fixed;
+ right: 0; top: 0;
+ padding: 10px 15px;
+ margin:0;
+}
+
+#jump_wrapper {
+ display: none;
+ padding:0;
+}
+
+#jump_to:hover #jump_wrapper {
+ display: block;
+}
+
+#jump_page {
+ padding: 5px 0 3px;
+ margin: 0 0 25px 25px;
+}
+
+#jump_page .source {
+ display: block;
+ padding: 15px;
+ text-decoration: none;
+ border-top: 1px solid #eee;
+}
+
+#jump_page .source:hover {
+ background: #f5f5ff;
+}
+
+#jump_page .source:first-child {
+}
+
+/*---------------------- Low resolutions (> 320px) ---------------------*/
+@media only screen and (min-width: 320px) {
+ .pilwrap { display: none; }
+
+ ul.sections > li > div {
+ display: block;
+ padding:5px 10px 0 10px;
+ }
+
+ ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
+ padding-left: 30px;
+ }
+
+ ul.sections > li > div.content {
+ background: #f5f5ff;
+ overflow-x:auto;
+ -webkit-box-shadow: inset 0 0 5px #e5e5ee;
+ box-shadow: inset 0 0 5px #e5e5ee;
+ border: 1px solid #dedede;
+ margin:5px 10px 5px 10px;
+ padding-bottom: 5px;
+ }
+
+ ul.sections > li > div.annotation pre {
+ margin: 7px 0 7px;
+ padding-left: 15px;
+ }
+
+ ul.sections > li > div.annotation p tt, .annotation code {
+ background: #f8f8ff;
+ border: 1px solid #dedede;
+ font-size: 12px;
+ padding: 0 0.2em;
+ }
+}
+
+/*---------------------- (> 481px) ---------------------*/
+@media only screen and (min-width: 481px) {
+ #container {
+ position: relative;
+ }
+ body {
+ background-color: #F5F5FF;
+ font-size: 15px;
+ line-height: 21px;
+ }
+ pre, tt, code {
+ line-height: 18px;
+ }
+ p, ul, ol {
+ margin: 0 0 15px;
+ }
+
+
+ #jump_to {
+ padding: 5px 10px;
+ }
+ #jump_wrapper {
+ padding: 0;
+ }
+ #jump_to, #jump_page {
+ font: 10px Arial;
+ text-transform: uppercase;
+ }
+ #jump_page .source {
+ padding: 5px 10px;
+ }
+ #jump_to a.large {
+ display: inline-block;
+ }
+ #jump_to a.small {
+ display: none;
+ }
+
+
+
+ #background {
+ position: absolute;
+ top: 0; bottom: 0;
+ width: 350px;
+ background: #fff;
+ border-right: 1px solid #e5e5ee;
+ z-index: -1;
+ }
+
+ ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
+ padding-left: 40px;
+ }
+
+ ul.sections > li {
+ white-space: nowrap;
+ }
+
+ ul.sections > li > div {
+ display: inline-block;
+ }
+
+ ul.sections > li > div.annotation {
+ max-width: 350px;
+ min-width: 350px;
+ min-height: 5px;
+ padding: 13px;
+ overflow-x: hidden;
+ white-space: normal;
+ vertical-align: top;
+ text-align: left;
+ }
+ ul.sections > li > div.annotation pre {
+ margin: 15px 0 15px;
+ padding-left: 15px;
+ }
+
+ ul.sections > li > div.content {
+ padding: 13px;
+ vertical-align: top;
+ background: #f5f5ff;
+ border: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+
+ .pilwrap {
+ position: relative;
+ display: inline;
+ }
+
+ .pilcrow {
+ font: 12px Arial;
+ text-decoration: none;
+ color: #454545;
+ position: absolute;
+ top: 3px; left: -20px;
+ padding: 1px 2px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ }
+ .for-h1 .pilcrow {
+ top: 47px;
+ }
+ .for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
+ top: 35px;
+ }
+
+ ul.sections > li > div.annotation:hover .pilcrow {
+ opacity: 1;
+ }
+}
+
+/*---------------------- (> 1025px) ---------------------*/
+@media only screen and (min-width: 1025px) {
+
+ body {
+ font-size: 16px;
+ line-height: 24px;
+ }
+
+ #background {
+ width: 525px;
+ }
+ ul.sections > li > div.annotation {
+ max-width: 525px;
+ min-width: 525px;
+ padding: 10px 25px 1px 50px;
+ }
+ ul.sections > li > div.content {
+ padding: 9px 15px 16px 25px;
+ }
+}
+
+/*---------------------- Syntax Highlighting -----------------------------*/
+
+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
+/*
+
+github.com style (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+
+pre code {
+ display: block; padding: 0.5em;
+ color: #000;
+ background: #f8f8ff
+}
+
+pre .comment,
+pre .template_comment,
+pre .diff .header,
+pre .javadoc {
+ color: #408080;
+ font-style: italic
+}
+
+pre .keyword,
+pre .assignment,
+pre .literal,
+pre .css .rule .keyword,
+pre .winutils,
+pre .javascript .title,
+pre .lisp .title,
+pre .subst {
+ color: #954121;
+ /*font-weight: bold*/
+}
+
+pre .number,
+pre .hexcolor {
+ color: #40a070
+}
+
+pre .string,
+pre .tag .value,
+pre .phpdoc,
+pre .tex .formula {
+ color: #219161;
+}
+
+pre .title,
+pre .id {
+ color: #19469D;
+}
+pre .params {
+ color: #00F;
+}
+
+pre .javascript .title,
+pre .lisp .title,
+pre .subst {
+ font-weight: normal
+}
+
+pre .class .title,
+pre .haskell .label,
+pre .tex .command {
+ color: #458;
+ font-weight: bold
+}
+
+pre .tag,
+pre .tag .title,
+pre .rules .property,
+pre .django .tag .keyword {
+ color: #000080;
+ font-weight: normal
+}
+
+pre .attribute,
+pre .variable,
+pre .instancevar,
+pre .lisp .body {
+ color: #008080
+}
+
+pre .regexp {
+ color: #B68
+}
+
+pre .class {
+ color: #458;
+ font-weight: bold
+}
+
+pre .symbol,
+pre .ruby .symbol .string,
+pre .ruby .symbol .keyword,
+pre .ruby .symbol .keymethods,
+pre .lisp .keyword,
+pre .tex .special,
+pre .input_number {
+ color: #990073
+}
+
+pre .builtin,
+pre .constructor,
+pre .built_in,
+pre .lisp .title {
+ color: #0086b3
+}
+
+pre .preprocessor,
+pre .pi,
+pre .doctype,
+pre .shebang,
+pre .cdata {
+ color: #999;
+ font-weight: bold
+}
+
+pre .deletion {
+ background: #fdd
+}
+
+pre .addition {
+ background: #dfd
+}
+
+pre .diff .change {
+ background: #0086b3
+}
+
+pre .chunk {
+ color: #aaa
+}
+
+pre .tex .formula {
+ opacity: 0.5;
+}
diff --git a/code/spyglass/docs/logging.html b/code/spyglass/docs/logging.html
new file mode 100644
index 0000000..5c4262a
--- /dev/null
+++ b/code/spyglass/docs/logging.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>logging.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>logging.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="class"><span class="keyword">module</span> <span class="title">Logging</span></span>
+ <span class="function"><span class="keyword">def</span> <span class="title">out</span><span class="params">(message)</span></span>
+ <span class="variable">$stdout</span>.puts preamble + message
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">err</span><span class="params">(message)</span></span>
+ <span class="variable">$stderr</span>.puts preamble + message
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">verbose</span><span class="params">(message)</span></span>
+ <span class="keyword">return</span> <span class="keyword">unless</span> <span class="constant">Config</span>.verbose
+ out(message)
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">vverbose</span><span class="params">(message)</span></span>
+ <span class="keyword">return</span> <span class="keyword">unless</span> <span class="constant">Config</span>.vverbose
+ out(message)
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">preamble</span></span>
+ <span class="string">"[<span class="subst">#{<span class="constant">Process</span>.pid}</span>] [<span class="subst">#{<span class="keyword">self</span>.<span class="keyword">class</span>.name}</span>] "</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/lookout.html b/code/spyglass/docs/lookout.html
new file mode 100644
index 0000000..a017f33
--- /dev/null
+++ b/code/spyglass/docs/lookout.html
@@ -0,0 +1,325 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>lookout.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>lookout.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="class"><span class="keyword">class</span> <span class="title">Lookout</span></span>
+ <span class="keyword">include</span> <span class="constant">Singleton</span>, <span class="constant">Logging</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <p>This method is the main entry point for the Lookout class. It takes
+a socket object.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(socket)</span></span>
+ trap_signals</pre></div></div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+ <p>The Lookout doesn&#39;t know anything about the app itself, so there&#39;s
+no app related setup to do here.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> loop <span class="keyword">do</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-4">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-4">&#182;</a>
+ </div>
+ <p>Accepts a new connection on our socket. This class won&#39;t actually
+do anything interesting with this connection, it will pass it down
+to the <code>Master</code> class created below to do the actual request handling.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> conn = socket.accept
+ out <span class="string">"Received incoming connection"</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-5">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-5">&#182;</a>
+ </div>
+ <p>In this block the Lookout forks a new process and invokes a Master,
+passing along the socket it received and the connection it accepted
+above.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@master_pid</span> = fork <span class="keyword">do</span>
+ master = <span class="constant">Master</span>.new(conn, socket)
+ master.start
+ <span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-6">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-6">&#182;</a>
+ </div>
+ <p>The Lookout can now close its handle on the client socket. This doesn&#39;t
+translate to the socket being closed on the clients end because the
+forked Master process also has a handle on the same socket. Since this
+handle is now cleaned up it&#39;s up to the Master process to ensure that
+its handle gets cleaned up.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> conn.close</pre></div></div>
+
+ </li>
+
+
+ <li id="section-7">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-7">&#182;</a>
+ </div>
+ <p>Now this process blocks until the Master process exits. The Master process
+will only exit once traffic is slow enough that it has reached its timeout
+without receiving any new connections.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="constant">Process</span>.waitpid(<span class="variable">@master_pid</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-8">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-8">&#182;</a>
+ </div>
+ <p>The interaction of fork(2)/waitpid(2) above deserve some explanation.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-9">
+ <div class="annotation">
+
+ <div class="pilwrap for-h3">
+ <a class="pilcrow" href="#section-9">&#182;</a>
+ </div>
+ <h3>Why fork(2)? Why not just spin up the Master?</h3>
+<p>The whole point of the Lookout process is to be very lean. The only resource
+that it initializes is the listening socket for the server. It doesn&#39;t load
+any of your application into memory, so its resource footprint is very small.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-10">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-10">&#182;</a>
+ </div>
+ <p>The reason that it does a fork(2) before invoking the Master is because once
+the Master times out we want the Lookout process to remain lean when accepting
+the next connection. </p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-11">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-11">&#182;</a>
+ </div>
+ <p>If it were to load the application code without forking
+then there would be no (simple) way for it to later unload the application code.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-12">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-12">&#182;</a>
+ </div>
+ <p>By doing a fork(2), then waiting for the Master process to exit, that guarantees
+that all resources (notably memory usage) that were in use by the Master process
+will be reclaimed by the kernel. </p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-13">
+ <div class="annotation">
+
+ <div class="pilwrap for-h3">
+ <a class="pilcrow" href="#section-13">&#182;</a>
+ </div>
+ <h3>Who knows what your app will demand!</h3>
+<p>While handling requests your app may require lots of memory. Containing this in a
+child process, and exiting that process, is the easiest way to ensure that memory
+bloat isn&#39;t shared with our simple parent process.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-14">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-14">&#182;</a>
+ </div>
+ <p>This allows our Lookout process will to go back around
+the loop with nothing more than it started with, just a listening socket.</p>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-15">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-15">&#182;</a>
+ </div>
+ <p>The fork(2)/waitpid(2) approach requires little code to implement, and pushes
+responsibility down to the kernel to track resource usage and nicely clean up
+the Master process when it&#39;s finished.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">trap_signals</span></span>
+ [<span class="symbol">:INT</span>, <span class="symbol">:QUIT</span>].each <span class="keyword">do</span> |sig|
+ trap(sig) {
+ <span class="keyword">begin</span>
+ <span class="constant">Process</span>.kill(sig, <span class="variable">@master_pid</span>) <span class="keyword">if</span> <span class="variable">@master_pid</span>
+ <span class="keyword">rescue</span> <span class="constant">Errno::ESRCH</span>
+ <span class="keyword">end</span>
+ exit
+ }
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/master.html b/code/spyglass/docs/master.html
new file mode 100644
index 0000000..11f2abc
--- /dev/null
+++ b/code/spyglass/docs/master.html
@@ -0,0 +1,268 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>master.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>master.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="class"><span class="keyword">class</span> <span class="title">Master</span></span>
+ <span class="keyword">include</span> <span class="constant">Logging</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(connection, socket)</span></span>
+ <span class="variable">@connection</span>, <span class="variable">@socket</span> = connection, socket
+ <span class="variable">@worker_pids</span> = []</pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <p>The Master shares this pipe with each of its worker processes. It
+passes the writable end down to each spawned worker while it listens
+on the readable end. Each worker will write to the pipe each time
+it accepts a new connection. If The Master doesn&#39;t get anything on
+the pipe before <code>Config.timeout</code> elapses then it kills its workers
+and exits. </p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@readable_pipe</span>, <span class="variable">@writable_pipe</span> = <span class="constant">IO</span>.pipe
+ <span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+ <p>This method starts the Master. It enters an infinite loop where it creates
+processes to handle web requests and ensures that they stay active. It takes
+a connection as an argument from the Lookout instance. A Master will only
+be started when a connection is received by the Lookout.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="function"><span class="keyword">def</span> <span class="title">start</span></span>
+ trap_signals
+
+ load_app
+ out <span class="string">"Loaded the app"</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-4">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-4">&#182;</a>
+ </div>
+ <p>The first worker we spawn has to handle the connection that was already
+passed to us.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> spawn_worker(<span class="variable">@connection</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-5">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-5">&#182;</a>
+ </div>
+ <p>The Master can now close its handle on the client socket since the
+forked worker also got a handle on the same socket. Since this one
+is now closed it&#39;s up to the Worker process to close its handle when
+it&#39;s done. At that point the client connection will perceive that
+it&#39;s been closed on their end.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@connection</span>.close</pre></div></div>
+
+ </li>
+
+
+ <li id="section-6">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-6">&#182;</a>
+ </div>
+ <p>We spawn the rest of the workers.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> (<span class="constant">Config</span>.workers - <span class="number">1</span>).times { spawn_worker }
+ out <span class="string">"Spawned <span class="subst">#{<span class="constant">Config</span>.workers}</span> workers. Babysitting now..."</span>
+
+ loop <span class="keyword">do</span>
+ <span class="keyword">if</span> timed_out?(<span class="constant">IO</span>.select([<span class="variable">@readable_pipe</span>], <span class="keyword">nil</span>, <span class="keyword">nil</span>, <span class="constant">Config</span>.timeout))
+ out <span class="string">"Timed out after <span class="subst">#{<span class="constant">Config</span>.timeout}</span> s. Exiting."</span>
+
+ kill_workers(<span class="symbol">:QUIT</span>)
+ exit
+ <span class="keyword">else</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-7">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-7">&#182;</a>
+ </div>
+ <p>Clear the data on the pipe so it doesn&#39;t appear to be readable
+next time around the loop.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@readable_pipe</span>.read_nonblock <span class="number">1</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">timed_out?</span><span class="params">(select_result)</span></span>
+ !select_result
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">spawn_worker</span><span class="params">(connection = <span class="keyword">nil</span>)</span></span>
+ <span class="variable">@worker_pids</span> &lt;&lt; fork { <span class="constant">Worker</span>.new(<span class="variable">@socket</span>, <span class="variable">@app</span>, <span class="variable">@writable_pipe</span>, connection).start }
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">trap_signals</span></span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-8">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-8">&#182;</a>
+ </div>
+ <p>The QUIT signal triggers a graceful shutdown. The master shuts down
+immediately and lets each worker finish the request they are currently
+processing.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> trap(<span class="symbol">:QUIT</span>) <span class="keyword">do</span>
+ verbose <span class="string">"Received QUIT"</span>
+
+ kill_workers(<span class="symbol">:QUIT</span>)
+ exit
+ <span class="keyword">end</span>
+
+ trap(<span class="symbol">:CHLD</span>) <span class="keyword">do</span>
+ dead_worker = <span class="constant">Process</span>.wait
+ <span class="variable">@worker_pids</span>.delete(dead_worker)
+
+ <span class="variable">@worker_pids</span>.each <span class="keyword">do</span> |wpid|
+ <span class="keyword">begin</span>
+ dead_worker = <span class="constant">Process</span>.waitpid(wpid, <span class="constant">Process::WNOHANG</span>)
+ <span class="variable">@worker_pids</span>.delete(dead_worker)
+ <span class="keyword">rescue</span> <span class="constant">Errno::ECHILD</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ spawn_worker
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">kill_workers</span><span class="params">(sig)</span></span>
+ <span class="variable">@worker_pids</span>.each <span class="keyword">do</span> |wpid|
+ <span class="constant">Process</span>.kill(sig, wpid)
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">load_app</span></span>
+ <span class="variable">@app</span>, options = <span class="constant">Rack::Builder</span>.parse_file(<span class="constant">Config</span>.config_ru_path)
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/public/fonts/aller-bold.eot b/code/spyglass/docs/public/fonts/aller-bold.eot
new file mode 100755
index 0000000..1b32532
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-bold.eot
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/aller-bold.ttf b/code/spyglass/docs/public/fonts/aller-bold.ttf
new file mode 100755
index 0000000..dc4cc9c
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-bold.ttf
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/aller-bold.woff b/code/spyglass/docs/public/fonts/aller-bold.woff
new file mode 100755
index 0000000..fa16fd0
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-bold.woff
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/aller-light.eot b/code/spyglass/docs/public/fonts/aller-light.eot
new file mode 100755
index 0000000..40bd654
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-light.eot
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/aller-light.ttf b/code/spyglass/docs/public/fonts/aller-light.ttf
new file mode 100755
index 0000000..c2c7290
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-light.ttf
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/aller-light.woff b/code/spyglass/docs/public/fonts/aller-light.woff
new file mode 100755
index 0000000..81a09d1
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/aller-light.woff
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/novecento-bold.eot b/code/spyglass/docs/public/fonts/novecento-bold.eot
new file mode 100755
index 0000000..98a9a7f
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/novecento-bold.eot
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/novecento-bold.ttf b/code/spyglass/docs/public/fonts/novecento-bold.ttf
new file mode 100755
index 0000000..2af39b0
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/novecento-bold.ttf
Binary files differ
diff --git a/code/spyglass/docs/public/fonts/novecento-bold.woff b/code/spyglass/docs/public/fonts/novecento-bold.woff
new file mode 100755
index 0000000..de558b5
--- /dev/null
+++ b/code/spyglass/docs/public/fonts/novecento-bold.woff
Binary files differ
diff --git a/code/spyglass/docs/public/stylesheets/normalize.css b/code/spyglass/docs/public/stylesheets/normalize.css
new file mode 100644
index 0000000..73abb76
--- /dev/null
+++ b/code/spyglass/docs/public/stylesheets/normalize.css
@@ -0,0 +1,375 @@
+/*! normalize.css v2.0.1 | MIT License | git.io/normalize */
+
+/* ==========================================================================
+ HTML5 display definitions
+ ========================================================================== */
+
+/*
+ * Corrects `block` display not defined in IE 8/9.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/*
+ * Corrects `inline-block` display not defined in IE 8/9.
+ */
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+/*
+ * Prevents modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/*
+ * Addresses styling for `hidden` attribute not present in IE 8/9.
+ */
+
+[hidden] {
+ display: none;
+}
+
+/* ==========================================================================
+ Base
+ ========================================================================== */
+
+/*
+ * 1. Sets default font family to sans-serif.
+ * 2. Prevents iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+ -ms-text-size-adjust: 100%; /* 2 */
+}
+
+/*
+ * Removes default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Links
+ ========================================================================== */
+
+/*
+ * Addresses `outline` inconsistency between Chrome and other browsers.
+ */
+
+a:focus {
+ outline: thin dotted;
+}
+
+/*
+ * Improves readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* ==========================================================================
+ Typography
+ ========================================================================== */
+
+/*
+ * Addresses `h1` font sizes within `section` and `article` in Firefox 4+,
+ * Safari 5, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+}
+
+/*
+ * Addresses styling not present in IE 8/9, Safari 5, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/*
+ * Addresses style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/*
+ * Addresses styling not present in Safari 5 and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/*
+ * Addresses styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+
+/*
+ * Corrects font family set oddly in Safari 5 and Chrome.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 1em;
+}
+
+/*
+ * Improves readability of pre-formatted text in all browsers.
+ */
+
+pre {
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+/*
+ * Sets consistent quote types.
+ */
+
+q {
+ quotes: "\201C" "\201D" "\2018" "\2019";
+}
+
+/*
+ * Addresses inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/*
+ * Prevents `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* ==========================================================================
+ Embedded content
+ ========================================================================== */
+
+/*
+ * Removes border when inside `a` element in IE 8/9.
+ */
+
+img {
+ border: 0;
+}
+
+/*
+ * Corrects overflow displayed oddly in IE 9.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* ==========================================================================
+ Figures
+ ========================================================================== */
+
+/*
+ * Addresses margin not present in IE 8/9 and Safari 5.
+ */
+
+figure {
+ margin: 0;
+}
+
+/* ==========================================================================
+ Forms
+ ========================================================================== */
+
+/*
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/*
+ * 1. Corrects color not being inherited in IE 8/9.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/*
+ * 1. Corrects font family not being inherited in all browsers.
+ * 2. Corrects font size not being inherited in all browsers.
+ * 3. Addresses margins set differently in Firefox 4+, Safari 5, and Chrome
+ */
+
+button,
+input,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/*
+ * Addresses Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+button,
+input {
+ line-height: normal;
+}
+
+/*
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Corrects inability to style clickable `input` types in iOS.
+ * 3. Improves usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button; /* 2 */
+ cursor: pointer; /* 3 */
+}
+
+/*
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+input[disabled] {
+ cursor: default;
+}
+
+/*
+ * 1. Addresses box sizing set to `content-box` in IE 8/9.
+ * 2. Removes excess padding in IE 8/9.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/*
+ * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
+ * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* 2 */
+ box-sizing: content-box;
+}
+
+/*
+ * Removes inner padding and search cancel button in Safari 5 and Chrome
+ * on OS X.
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/*
+ * Removes inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/*
+ * 1. Removes default vertical scrollbar in IE 8/9.
+ * 2. Improves readability and alignment in all browsers.
+ */
+
+textarea {
+ overflow: auto; /* 1 */
+ vertical-align: top; /* 2 */
+}
+
+/* ==========================================================================
+ Tables
+ ========================================================================== */
+
+/*
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+} \ No newline at end of file
diff --git a/code/spyglass/docs/server.html b/code/spyglass/docs/server.html
new file mode 100644
index 0000000..1f5a12b
--- /dev/null
+++ b/code/spyglass/docs/server.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>server.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>server.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+
+ <span class="class"><span class="keyword">class</span> <span class="title">Server</span></span>
+ <span class="keyword">include</span> <span class="constant">Singleton</span>
+ <span class="keyword">include</span> <span class="constant">Logging</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">start</span></span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <p>Opens the main listening socket for the server. Now the server is responsive to
+incoming connections.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> sock = <span class="constant">TCPServer</span>.open(<span class="constant">Config</span>.host, <span class="constant">Config</span>.port)
+ out <span class="string">"Listening on port <span class="subst">#{<span class="constant">Config</span>.host}</span>:<span class="subst">#{<span class="constant">Config</span>.port}</span>"</span>
+
+ <span class="constant">Lookout</span>.instance.start(sock)
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/spyglass.html b/code/spyglass/docs/spyglass.html
new file mode 100644
index 0000000..3c317a4
--- /dev/null
+++ b/code/spyglass/docs/spyglass.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>Spyglass</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul class="sections">
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap for-h1">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+ <h1>Spyglass</h1>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <p>This is Spyglass, a Rack web server that rides on Unix designed to be simple and teach
+others about Unix programming.</p>
+<p>It&#39;s namesake comes from the fact that when it boots up it&#39;s nothing more than a lone socket
+keeping a lookout for incoming connections. </p>
+<p>When a connection comes in it spins up a Master
+process which preforks some workers to actually handle http requests. If the Master process is
+left idle long enough it will shut itself (and it&#39;s workers) down and go back to just a lone
+listening socket, on the lookout for incoming connections.</p>
+<h1>Components</h1>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+ <ul>
+<li><p><a href="server.html">Server</a> gets the ball rolling.
+The role of Server is pretty minimal. It opens the initial listening TCP socket,
+then passes that socket onto the Lookout. The Lookout will actually handle reading
+from the socket.</p>
+</li>
+<li><p><a href="lookout.html">Lookout</a> keeps a watch and notifies others when a connection
+comes in.
+The Lookout is a pretty &#39;dumb&#39; object. All that it does is listen for incoming
+connections on the socket it&#39;s given. Once it receives a connection it does a fork(2)
+and invokes a Master process. The Master process actually handles the connection.</p>
+</li>
+<li><p><a href="master.html">Master</a> loads the application and babysits worker processes
+that actually talk to clients.
+The role of the Master class is to create and babysit worker processes
+that will actually handle web requests. The Master itself doesn&#39;t know
+anything about http, etc. it just knows how to manage processes.</p>
+</li>
+<li><p><a href="worker.html">Worker</a> parses HTTP, calls the app, and writes back to the client.</p>
+</li>
+</ul>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="keyword">require</span> <span class="string">'singleton'</span>
+<span class="keyword">require</span> <span class="string">'socket'</span>
+<span class="keyword">require</span> <span class="string">'stringio'</span>
+
+<span class="keyword">require</span> <span class="string">'rack/server'</span>
+<span class="keyword">require</span> <span class="string">'rack/builder'</span>
+
+<span class="keyword">require</span> <span class="string">'spyglass_parser'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/configurator'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/logging'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/server'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/lookout'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/master'</span>
+<span class="keyword">require</span> <span class="string">'spyglass/worker'</span>
+
+<span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="constant">Version</span> = <span class="string">'0.1.1'</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/code/spyglass/docs/worker.html b/code/spyglass/docs/worker.html
new file mode 100644
index 0000000..a511c99
--- /dev/null
+++ b/code/spyglass/docs/worker.html
@@ -0,0 +1,305 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>worker.rb</title>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
+ <link rel="stylesheet" media="all" href="docco.css" />
+</head>
+<body>
+ <div id="container">
+ <div id="background"></div>
+
+ <ul id="jump_to">
+ <li>
+ <a class="large" href="javascript:void(0);">Jump To &hellip;</a>
+ <a class="small" href="javascript:void(0);">+</a>
+ <div id="jump_wrapper">
+ <div id="jump_page">
+
+
+ <a class="source" href="configurator.html">
+ configurator.rb
+ </a>
+
+
+ <a class="source" href="logging.html">
+ logging.rb
+ </a>
+
+
+ <a class="source" href="lookout.html">
+ lookout.rb
+ </a>
+
+
+ <a class="source" href="master.html">
+ master.rb
+ </a>
+
+
+ <a class="source" href="server.html">
+ server.rb
+ </a>
+
+
+ <a class="source" href="worker.html">
+ worker.rb
+ </a>
+
+ </div>
+ </li>
+ </ul>
+
+ <ul class="sections">
+
+ <li id="title">
+ <div class="annotation">
+ <h1>worker.rb</h1>
+ </div>
+ </li>
+
+
+
+ <li id="section-1">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-1">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="keyword">require</span> <span class="string">'time'</span>
+<span class="keyword">require</span> <span class="string">'rack/utils'</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-2">
+ <div class="annotation">
+
+ <div class="pilwrap for-h1">
+ <a class="pilcrow" href="#section-2">&#182;</a>
+ </div>
+ <h1>Worker</h1>
+
+ </div>
+
+ </li>
+
+
+ <li id="section-3">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-3">&#182;</a>
+ </div>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre><span class="class"><span class="keyword">module</span> <span class="title">Spyglass</span></span>
+ <span class="class"><span class="keyword">class</span> <span class="title">Worker</span></span>
+ <span class="keyword">include</span> <span class="constant">Logging</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">initialize</span><span class="params">(socket, app, writable_pipe, connection = <span class="keyword">nil</span>)</span></span>
+ <span class="variable">@socket</span>, <span class="variable">@app</span>, <span class="variable">@writable_pipe</span> = socket, app, writable_pipe
+ <span class="variable">@parser</span> = <span class="constant">Spyglass::HttpParser</span>.new
+
+ handle_connection(connection) <span class="keyword">if</span> connection
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">start</span></span>
+ trap_signals
+
+ loop <span class="keyword">do</span>
+ handle_connection <span class="variable">@socket</span>.accept
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">handle_connection</span><span class="params">(conn)</span></span>
+ verbose <span class="string">"Received connection"</span></pre></div></div>
+
+ </li>
+
+
+ <li id="section-4">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-4">&#182;</a>
+ </div>
+ <p>This notifies our Master that we have received a connection, expiring
+it&#39;s <code>IO.select</code> and preventing it from timing out.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@writable_pipe</span>.write_nonblock(<span class="string">'.'</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-5">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-5">&#182;</a>
+ </div>
+ <p>This clears any state that the http parser has lying around
+from the last connection that was handled.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@parser</span>.reset</pre></div></div>
+
+ </li>
+
+
+ <li id="section-6">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-6">&#182;</a>
+ </div>
+ <p>The Rack spec requires that &#39;rack.input&#39; be encoded as ASCII-8BIT.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> empty_body = <span class="string">''</span>
+ empty_body.encode!(<span class="constant">Encoding::ASCII_8BIT</span>) <span class="keyword">if</span> empty_body.respond_to?(<span class="symbol">:encode!</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-7">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-7">&#182;</a>
+ </div>
+ <p>The Rack spec requires that the env contain certain keys before being
+passed to the app. These are the keys that aren&#39;t provided by each
+incoming request, server-specific stuff.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> env = {
+ <span class="string">'rack.input'</span> =&gt; <span class="constant">StringIO</span>.new(empty_body),
+ <span class="string">'rack.multithread'</span> =&gt; <span class="keyword">false</span>,
+ <span class="string">'rack.multiprocess'</span> =&gt; <span class="keyword">true</span>,
+ <span class="string">'rack.run_once'</span> =&gt; <span class="keyword">false</span>,
+ <span class="string">'rack.errors'</span> =&gt; <span class="constant">STDERR</span>,
+ <span class="string">'rack.version'</span> =&gt; [<span class="number">1</span>, <span class="number">0</span>]
+ }</pre></div></div>
+
+ </li>
+
+
+ <li id="section-8">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-8">&#182;</a>
+ </div>
+ <p>This reads data in from the client connection. We&#39;ll read up to
+10000 bytes at the moment.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> data = conn.readpartial(<span class="number">10000</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-9">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-9">&#182;</a>
+ </div>
+ <p>Here we pass the data and the env into the http parser. It parses
+the raw http request data and updates the env with all of the data
+it can withdraw.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> <span class="variable">@parser</span>.execute(env, data, <span class="number">0</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-10">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-10">&#182;</a>
+ </div>
+ <p>Call the Rack app, goes all the way down the rabbit hole and back again.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> status, headers, body = <span class="variable">@app</span>.call(env)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-11">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-11">&#182;</a>
+ </div>
+ <p>These are the default headers we always include in a response. We
+only speak HTTP 1.1 and we always close the client connection. At
+the monment keepalive is not supported.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> head = <span class="string">"HTTP/1.1 <span class="subst">#{status}</span>\r\n"</span> \
+ <span class="string">"Date: <span class="subst">#{<span class="constant">Time</span>.now.httpdate}</span>\r\n"</span> \
+ <span class="string">"Status: <span class="subst">#{<span class="constant">Rack::Utils::HTTP_STATUS_CODES</span>[status]}</span>\r\n"</span> \
+ <span class="string">"Connection: close\r\n"</span>
+
+ headers.each <span class="keyword">do</span> |k,v|
+ head &lt;&lt; <span class="string">"<span class="subst">#{k}</span>: <span class="subst">#{v}</span>\r\n"</span>
+ <span class="keyword">end</span>
+ conn.write <span class="string">"<span class="subst">#{head}</span>\r\n"</span>
+
+ body.each { |chunk| conn.write chunk }
+ body.close <span class="keyword">if</span> body.respond_to?(<span class="symbol">:close</span>)</pre></div></div>
+
+ </li>
+
+
+ <li id="section-12">
+ <div class="annotation">
+
+ <div class="pilwrap ">
+ <a class="pilcrow" href="#section-12">&#182;</a>
+ </div>
+ <p>Since keepalive is not supported we can close the client connection
+immediately after writing the body.</p>
+
+ </div>
+
+ <div class="content"><div class='highlight'><pre> conn.close
+
+ verbose <span class="string">"Closed connection"</span>
+ <span class="keyword">end</span>
+
+ <span class="function"><span class="keyword">def</span> <span class="title">trap_signals</span></span>
+ trap(<span class="symbol">:QUIT</span>) <span class="keyword">do</span>
+ out <span class="string">"Received QUIT"</span>
+ exit
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+ <span class="keyword">end</span>
+<span class="keyword">end</span></pre></div></div>
+
+ </li>
+
+ </ul>
+ </div>
+</body>
+</html>