rack-cache 0.2.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.

Potentially problematic release.


This version of rack-cache might be problematic. Click here for more details.

Files changed (44) hide show
  1. data/CHANGES +27 -0
  2. data/COPYING +18 -0
  3. data/README +96 -0
  4. data/Rakefile +144 -0
  5. data/TODO +40 -0
  6. data/doc/configuration.markdown +224 -0
  7. data/doc/events.dot +27 -0
  8. data/doc/faq.markdown +133 -0
  9. data/doc/index.markdown +113 -0
  10. data/doc/layout.html.erb +33 -0
  11. data/doc/license.markdown +24 -0
  12. data/doc/rack-cache.css +362 -0
  13. data/doc/storage.markdown +162 -0
  14. data/lib/rack/cache.rb +51 -0
  15. data/lib/rack/cache/config.rb +65 -0
  16. data/lib/rack/cache/config/busters.rb +16 -0
  17. data/lib/rack/cache/config/default.rb +134 -0
  18. data/lib/rack/cache/config/no-cache.rb +13 -0
  19. data/lib/rack/cache/context.rb +95 -0
  20. data/lib/rack/cache/core.rb +271 -0
  21. data/lib/rack/cache/entitystore.rb +224 -0
  22. data/lib/rack/cache/headers.rb +237 -0
  23. data/lib/rack/cache/metastore.rb +309 -0
  24. data/lib/rack/cache/options.rb +119 -0
  25. data/lib/rack/cache/request.rb +37 -0
  26. data/lib/rack/cache/response.rb +76 -0
  27. data/lib/rack/cache/storage.rb +50 -0
  28. data/lib/rack/utils/environment_headers.rb +78 -0
  29. data/rack-cache.gemspec +74 -0
  30. data/test/cache_test.rb +35 -0
  31. data/test/config_test.rb +66 -0
  32. data/test/context_test.rb +465 -0
  33. data/test/core_test.rb +84 -0
  34. data/test/entitystore_test.rb +176 -0
  35. data/test/environment_headers_test.rb +71 -0
  36. data/test/headers_test.rb +215 -0
  37. data/test/logging_test.rb +45 -0
  38. data/test/metastore_test.rb +210 -0
  39. data/test/options_test.rb +64 -0
  40. data/test/pony.jpg +0 -0
  41. data/test/response_test.rb +37 -0
  42. data/test/spec_setup.rb +189 -0
  43. data/test/storage_test.rb +94 -0
  44. metadata +120 -0
data/doc/events.dot ADDED
@@ -0,0 +1,27 @@
1
+ digraph cache_logic {
2
+ nodesep=1.25;
3
+ center=true;
4
+
5
+ node[fontname="Lucida Sans Unicode",labelloc=c,margin=0.10,0.03]
6
+ edge[fontname="Lucida Sans Unicode",fontcolor="#444444",labeldistance=20];
7
+
8
+ receive -> pass[label="uncacheable request",color=grey];
9
+ receive -> lookup[label="cacheable request"];
10
+
11
+ pass -> deliver[label="",color=grey];
12
+
13
+ lookup -> hit[label="fresh"];
14
+ lookup -> fetch[label="stale (needs validation)"];
15
+ lookup -> miss[label="uncached"];
16
+
17
+ hit -> deliver[label="sizzling"];
18
+ hit -> pass[label="bailing...",color=grey];
19
+
20
+ miss -> fetch[label=""];
21
+ miss -> pass[color=grey];
22
+
23
+ fetch -> store[label="cacheable"];
24
+ fetch -> deliver[label="not cacheable",color=grey];
25
+
26
+ store -> deliver[label="KTHX"];
27
+ }
data/doc/faq.markdown ADDED
@@ -0,0 +1,133 @@
1
+ Frequently Asked Questions
2
+ ==========================
3
+
4
+ <p class='intro'>
5
+ <strong>NOTE:</strong> This is a work in progress. Please send questions, comments, or
6
+ suggestions to <a href="mailto:r@tomayko.com">r@tomayko.com</a>.
7
+ </p>
8
+
9
+ General
10
+ -------
11
+
12
+
13
+ <a class='hash' id='why-not-squid' href='#why-not-squid'>#</a>
14
+
15
+ ### Q: Why Rack::Cache? Why not Squid, Varnish, Perlbol, etc.?
16
+
17
+ __Rack::Cache__ is often easier to setup as part of your existing Ruby
18
+ application than a separate caching system. __Rack::Cache__ runs entirely inside
19
+ your backend application processes - no separate / external process is required.
20
+ This lets __Rack::Cache__ scale down to development environments and simple
21
+ deployments very easily while not sacrificing the benefits of a standards-based
22
+ approach to caching.
23
+
24
+
25
+ <a class='hash' id='why-not-rails' href='#why-not-rails'>#</a>
26
+
27
+ ### Q: Why Rack::Cache? Why not use Rails/Merb/FrameworkX's caching system?
28
+
29
+ __Rack::Cache__ takes a standards-based approach to caching that provides some
30
+ benefits over framework-integrated systems. It uses standard HTTP headers
31
+ (`Expires`, `Cache-Control`, `Etag`, `Last-Modified`, etc.) to determine
32
+ what/when to cache. Designing applications to support these standard HTTP
33
+ mechanisms gives the benefit of being able to switch to a different HTTP
34
+ cache implementation in the future.
35
+
36
+ In addition, using a standards-based approach to caching creates a clear
37
+ separation between application and caching logic. The application need only
38
+ specify a basic set of information about the response and all decisions
39
+ regarding how and when to cache is moved into the caching layer.
40
+
41
+
42
+ <a class='hash' id='scale' href='#scale'>#</a>
43
+
44
+ ### Q: Will Rack::Cache make my app scale?
45
+
46
+ No. Your design is the only thing that can make your app scale.
47
+
48
+ Also, __Rack::Cache__ is not overly optimized for performance. The main goal of
49
+ the project is to provide a portable, easy-to-configure, and standards-based
50
+ caching solution for small to medium sized deployments. More sophisticated /
51
+ performant caching systems (e.g., [Varnish][v], [Squid][s],
52
+ [httpd/mod-cache][h]) may be more appropriate for large deployments with
53
+ crazy-land throughput requirements.
54
+
55
+ [v]: http://varnish.projects.linpro.no/
56
+ [s]: http://www.squid-cache.org/
57
+ [h]: http://httpd.apache.org/docs/2.0/mod/mod_cache.html
58
+
59
+
60
+ Features
61
+ --------
62
+
63
+
64
+ <a class='hash' id='validation' href='#validation'>#</a>
65
+
66
+ ### Q: Does Rack::Cache support validation?
67
+
68
+ Yes. Both freshness and validation-based caching is supported. A response
69
+ will be cached if it has a freshness lifetime (e.g., `Expires` or
70
+ `Cache-Control: max-age=N` headers) and/or includes a validator (e.g.,
71
+ `Last-Modified` or `ETag` headers). When the cache hits and the response is
72
+ fresh, it's delivered immediately without talking to the backend application;
73
+ when the cache is stale, the cached response is validated using a conditional
74
+ GET request.
75
+
76
+
77
+ <a class='hash' id='fragments' href='#fragments'>#</a>
78
+
79
+ ### Q: Does Rack::Cache support fragment caching?
80
+
81
+ Not really. __Rack::Cache__ deals with entire responses and doesn't know
82
+ anything about how your application constructs them.
83
+
84
+ However, something like [ESI](http://www.w3.org/TR/esi-lang) may be implemented
85
+ in the future (likely as a separate Rack middleware component that could be
86
+ situated upstream from Rack::Cache), which would allow applications to compose
87
+ responses based on several "fragment resources". Each fragment would have its
88
+ own cache policy.
89
+
90
+
91
+ <a class='hash' id='manual-purge' href='#manual-purge'>#</a>
92
+
93
+ ### Q: How do I manually purge or expire a cached entry?
94
+
95
+ Although planned, there is currently no mechanism for manually purging
96
+ an entry stored in the cache.
97
+
98
+ Note that using an `Expires` or `Cache-Control: max-age=N` header and relying on
99
+ manual purge to invalidate cached entry can often be implemented more simply
100
+ using efficient validation based caching (`Last-Modified`, `Etag`). Many web
101
+ frameworks are based entirely on manual purge and do not support validation at
102
+ the cache level.
103
+
104
+
105
+ <a class='hash' id='efficient-validation' href='#efficient-validation'>#</a>
106
+
107
+ ### Q: What does "Efficient Validation" mean?
108
+
109
+ It means that your application performs only the processing necessary to
110
+ determine if a response is valid before sending a `304 Not Modified` in response
111
+ to a conditional GET request. Many applications that perform validation do so
112
+ only after the entire response has been generated, which provides bandwidth
113
+ savings but results in no CPU/IO savings. Implementing validation efficiently
114
+ can increase backend application throughput significantly when fronted by a
115
+ validating caching system (like __Rack::Cache__).
116
+
117
+ [Here's an example Rack application](http://gist.github.com/9395) that performs
118
+ efficient validation.
119
+
120
+
121
+ <a class='hash' id='orly' href='#orly'>#</a>
122
+
123
+ ### Q: Did you just make that up?
124
+
125
+ Yes.
126
+
127
+
128
+ <a class='hash' id='https' href='#https'>#</a>
129
+
130
+ ### Q: Can I do HTTPS with Rack::Cache?
131
+
132
+ Sure. HTTPS is typically managed by a front-end web server so this isn't really
133
+ relevant to Rack::Cache.
@@ -0,0 +1,113 @@
1
+ __Rack::Cache__ is suitable as a quick drop-in component to enable HTTP caching
2
+ for [Rack][]-based applications that produce freshness (`Expires`,
3
+ `Cache-Control`) and/or validation (`Last-Modified`, `ETag`) information.
4
+
5
+ * Standards-based ([RFC 2616][rfc] / [Section 13][s13]).
6
+ * Freshness/expiration based caching
7
+ * Validation
8
+ * Vary Support
9
+ * Portable: 100% Ruby / works with any [Rack][]-enabled framework.
10
+ * [Configuration language][config] for advanced caching policies.
11
+ * Disk, memcached, and heap memory [storage backends][storage].
12
+
13
+ Status
14
+ ------
15
+
16
+ __Rack::Cache__ is a young and experimental project that is likely to
17
+ change substantially and may not be wholly functional, consistent,
18
+ fast, or correct. The current focus is on reaching basic compliance
19
+ with RFC 2616 and providing good documentation.
20
+
21
+ Installation
22
+ ------------
23
+
24
+ $ sudo gem install rack-cache
25
+
26
+ Or, from a local working copy:
27
+
28
+ $ git clone git://github.com/rtomayko/rack-cache.git
29
+ $ rake package && sudo rake install
30
+
31
+ Basic Usage
32
+ -----------
33
+
34
+ __Rack::Cache__ is implemented as a piece of [Rack][] middleware and can be used
35
+ with any __Rack__-based application. If your application includes a rackup
36
+ (`.ru`) file or uses __Rack::Builder__ to construct the application pipeline,
37
+ simply `require` and `use` as follows:
38
+
39
+ require 'rack/cache'
40
+
41
+ use Rack::Cache,
42
+ :verbose => true,
43
+ :metastore => 'file:/var/cache/rack/meta'
44
+ :entitystore => 'file:/var/cache/rack/body'
45
+
46
+ run app
47
+
48
+ Assuming you've designed your backend application to take advantage of HTTP's
49
+ caching features, no further code or configuration is required for basic
50
+ caching. More sophisticated stuff is possible with [Rack::Cache's Configuration
51
+ Language][config].
52
+
53
+ Advanced Usage
54
+ --------------
55
+
56
+ * [Configuration Language Documentation][config] - How to customize cache
57
+ policy using the simple event-based configuration system.
58
+
59
+ * [Cache Storage Documentation][storage] - Detailed information on the various
60
+ storage implementations available in __Rack::Cache__ and how to choose the one
61
+ that's best for your application.
62
+
63
+ * [FAQ](./faq) - Frequently Asked Questions about __Rack::Cache__.
64
+
65
+ * [GitHub Repository](http://github.com/rtomayko/rack-cache/) - Get your
66
+ fork on.
67
+
68
+ * [RDoc API Documentation](./api/) - Mostly worthless if you just want to use
69
+ __Rack::Cache__ in your application but mildly insightful if you'd like to
70
+ get a feel for how the system has been put together; I recommend
71
+ [reading the source](http://github.com/rtomayko/rack-cache/master/lib/rack/cache).
72
+
73
+ See Also
74
+ --------
75
+
76
+ The overall design of __Rack::Cache__ is based largely on the work of the
77
+ internet standards community. The following resources provide a good starting
78
+ point for exploring the basic concepts of HTTP caching:
79
+
80
+ * Mark Nottingham's [Caching Tutorial](http://www.mnot.net/cache_docs/),
81
+ especially the short section on
82
+ [How Web Caches Work](http://www.mnot.net/cache_docs/#WORK)
83
+
84
+ * Joe Gregorio's [Doing HTTP Caching Right](http://www.xml.com/lpt/a/1642)
85
+
86
+ * [RFC 2616](http://www.ietf.org/rfc/rfc2616.txt), especially
87
+ [Section 13, "Caching in HTTP"](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html)
88
+
89
+ __Rack::Cache__ takes (_liberally_) various concepts from
90
+ [Varnish](http://varnish.projects.linpro.no/) and
91
+ [Django's cache framework](http://docs.djangoproject.com/en/dev/topics/cache/).
92
+
93
+ License
94
+ -------
95
+
96
+ __Rack::Cache__ is Copyright &copy; 2008
97
+ by [Ryan Tomayko](http://tomayko.com/about)
98
+ and is provided under [the MIT license](./license)
99
+
100
+ [config]: ./configuration "Rack::Cache Configuration Language Documentation"
101
+ [storage]: ./storage "Rack::Cache Storage Documentation"
102
+
103
+ [rfc]: http://tools.ietf.org/html/rfc2616
104
+ "RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 [ietf.org]"
105
+
106
+ [s13]: http://tools.ietf.org/html/rfc2616#section-13
107
+ "RFC 2616 / Section 13 Caching in HTTP"
108
+
109
+ [rack]: http://rack.rubyforge.org/
110
+ "Rack: a Ruby Webserver Interface"
111
+
112
+ [vcl]: http://tomayko.com/man/vcl
113
+ "VCL(7) -- Varnish Configuration Language Manual Page"
@@ -0,0 +1,33 @@
1
+ <!DOCTYPE html>
2
+ <html lang='en'>
3
+ <head>
4
+ <meta http-equiv='Content-Type' content='text/html;charset=utf-8'>
5
+ <title>Rack::Cache <%= title %></title>
6
+ <link rel='stylesheet' href='rack-cache.css' type='text/css' media='all'>
7
+ <script type='text/javascript' src='http://code.jquery.com/jquery-1.2.3.js'></script>
8
+ <script type='text/javascript' src='http://tomayko.com/js/tomayko.js'></script>
9
+ </head>
10
+ <body>
11
+ <div id='container'>
12
+ <div id='header'>
13
+ <h1><a href="./">rack-cache</a></h1>
14
+ <p>
15
+ <a href="./configuration" title='Configuration Language Documentation'>Config</a> |
16
+ <a href="./storage" title='Cache Storage Documentation'>Storage</a> |
17
+ <a href="./faq" title='Frequently Asked Questions'>FAQ</a> |
18
+ <a href="./api/" title='Fucking Sucks.'>RDoc</a>
19
+ </p>
20
+ </div>
21
+ <div id='content'><%= content %></div>
22
+ <div id='footer'>
23
+ <p class='rights'>
24
+ Copyright
25
+ <a href="./license" rel="license">&copy;</a>
26
+ 2003-2008
27
+ by
28
+ <a href='http://tomayko.com/about' rel='me author'>Ryan Tomayko</a>
29
+ </p>
30
+ </div>
31
+ </div>
32
+ </body>
33
+ </html>
@@ -0,0 +1,24 @@
1
+ License (MIT)
2
+ =============
3
+
4
+ __Rack::Cache__ is Copyright &copy; 2008
5
+ by [Ryan Tomayko](http://tomayko.com/about)
6
+
7
+ <pre class='license'>
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to
10
+ deal in the Software without restriction, including without limitation the
11
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12
+ sell copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
22
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ </pre>
@@ -0,0 +1,362 @@
1
+ /* rack-cache.css
2
+ *---------------------------------------------------------------------------
3
+ * Copyright (C) 2005-08 Ryan Tomayko <r@tomayko.com>
4
+ */
5
+
6
+
7
+ /* 18px base font size / 25px baseline */
8
+ body {
9
+ font-size:112.5%; /* 18px (probably) */
10
+ line-height:1.3888; /* 25px */
11
+ letter-spacing:-0.02em;
12
+ margin:0 10px;
13
+ font-family: 'lucida sans unicode', 'lucida grande',
14
+ helvetica, 'bitstream vera sans', sans-serif;
15
+ color:#556;
16
+ background-color:#fff;
17
+ }
18
+
19
+ #container {
20
+ max-width:45em;
21
+ margin:0 auto;
22
+ }
23
+
24
+ h1, h2, h3 {
25
+ font-family:georgia, 'bitstream vera sans serif', 'lucida grande',
26
+ helvetica, verdana, sans-serif;
27
+ font-weight:normal;
28
+ letter-spacing:-0.05em;
29
+ color:#000;
30
+ }
31
+ i, em {
32
+ font-style:italic;
33
+ }
34
+ b, strong {
35
+ font-weight:normal;
36
+ color:#000;
37
+ }
38
+ blockquote {
39
+ color:#555;
40
+ }
41
+ blockquote em {
42
+ color:#333;
43
+ font-style:italic;
44
+ }
45
+ blockquote strong {
46
+ color:#333;
47
+ font-weight: normal;
48
+ }
49
+ dt {
50
+ font-weight:bold;
51
+ color:#000;
52
+ }
53
+ tt, pre, code, samp, kbd {
54
+ font-family: consolas, 'lucida console', 'bitstream vera sans mono',
55
+ 'courier new', monospace;
56
+ color: #000;
57
+ }
58
+ pre {
59
+ color:#333;
60
+ background-color:#f9f9f9;
61
+ }
62
+ code {
63
+ color:#007A00;
64
+ }
65
+ pre code {
66
+ color:#333;
67
+ }
68
+ pre.license {
69
+ border:0;
70
+ background:#fff;
71
+ padding:0;
72
+ font-size:1.1em;
73
+ }
74
+ a, a:link {
75
+ color:#023;
76
+ background:#eef;
77
+ }
78
+ a:visited {
79
+ color:#345;
80
+ background:#fff;
81
+ }
82
+ a:hover {
83
+ background:#ccf;
84
+ color:#000;
85
+ text-decoration:none;
86
+ }
87
+
88
+
89
+ /* TYPOGRAPHY */
90
+
91
+ p, ul, ol, dl, pre, blockquote, table, form {
92
+ margin:1em 0;
93
+ }
94
+ dl {
95
+ margin-left:2em;
96
+ }
97
+ hr {
98
+ color:#eee;
99
+ background-color:#ccc;
100
+ border:0;
101
+ height:1px;
102
+ margin:1.5em 0;
103
+ }
104
+ blockquote {
105
+ font-size:0.83333em; /* 15px */
106
+ line-height:1.66666; /* 25px */
107
+ margin:1.2em 3em;
108
+ padding:0;
109
+ }
110
+ tt, pre, code, samp, kbd {
111
+ font-size: 16px;
112
+ line-height:1.1;
113
+ }
114
+ pre {
115
+ margin:1.5em 0;
116
+ padding:6px 4px 4px 6px;
117
+ border:1px solid #eee;
118
+ border-left-width:20px;
119
+ overflow:auto;
120
+ }
121
+ h1 {
122
+ font-size:2.3333em; /* 42px */
123
+ line-height:1.1904; /* 50px */
124
+ margin:0.5952em 0; /* 25px */
125
+ }
126
+ h2 {
127
+ font-size:1.66666667em; /* 30px */
128
+ line-height:1.2; /* 36px */
129
+ margin:1em 0;
130
+ }
131
+ h3 {
132
+ font-size:1.33333333em; /* 22px */
133
+ line-height:1.13636363; /* 25px */
134
+ margin:1em 0;
135
+ }
136
+ h3 code{
137
+ font-size:0.95em;
138
+ color:#000;
139
+ }
140
+ h4 {
141
+ font-size:1em;
142
+ font-weight:bold;
143
+ line-height:1.5;
144
+ margin:1em 0;
145
+ }
146
+ p small {
147
+ font-size:0.8333; /* 15px */
148
+ line-height:1.2;
149
+ }
150
+
151
+ /* Tables
152
+ --------------------------------------------------------------------------- */
153
+
154
+ table {
155
+ width:100%;
156
+ border-style:none;
157
+ border-color:#ddd;
158
+ padding:0;
159
+ }
160
+
161
+ th, td {
162
+ padding: 4px 10px 4px 5px;
163
+ border-style:solid;
164
+ border-color:#fff;
165
+ }
166
+
167
+ th {
168
+ font-weight: bold;
169
+ background: #eef;
170
+ }
171
+
172
+ td {
173
+ background: #f9f9f9;
174
+ }
175
+
176
+ tfoot {
177
+ font-style: italic;
178
+ }
179
+
180
+ caption {
181
+ background: #eee;
182
+ }
183
+
184
+ /* Header / Titling
185
+ --------------------------------------------------------------------------- */
186
+
187
+ #header {
188
+ text-align:left;
189
+ margin:1.5em auto 2em;
190
+ float:left;
191
+ width:100%;
192
+ padding-bottom:1.5em;
193
+ border-bottom:1px solid #777;
194
+ }
195
+ #header h1 {
196
+ font-family: 'lucida sans unicode', 'lucida grande',
197
+ helvetica, 'bitstream vera sans', sans-serif;
198
+ font-size:5em;
199
+ font-weight:bold;
200
+ line-height:1;
201
+ margin:0;
202
+ float:left;
203
+ color:#000;
204
+ letter-spacing:-0.08em;
205
+ }
206
+ #header h1 a, #header h1 a:link, #header h1 a:visited, #header h1 a:hover {
207
+ color:#000;
208
+ text-decoration:none;
209
+ background:transparent;
210
+ }
211
+ #header p {
212
+ margin: 0;
213
+ line-height:1.8;
214
+ color: #777;
215
+ text-transform:capitalize;
216
+ font-variant:small-caps;
217
+ float:right;
218
+ }
219
+ #header a, #header a:link, #header a:visited {
220
+ color:#445;
221
+ background:#fff;
222
+ }
223
+ #header a:hover {
224
+ background:#ccf;
225
+ color:#000;
226
+ text-decoration:none;
227
+ }
228
+ #content {
229
+ clear:both;
230
+ }
231
+
232
+ /* FOOTER */
233
+
234
+ #footer {
235
+ clear:both;
236
+ color:#555;
237
+ font-size:0.88888888em;
238
+ line-height:1.5625;
239
+ border-top:1px solid #ddd;
240
+ padding:19px 0 0 0;
241
+ margin:40px 0 20px 0;
242
+ text-align:center;
243
+ }
244
+ #footer p {
245
+ margin:0;
246
+ }
247
+ #footer form {
248
+ float:right;
249
+ }
250
+ #footer input{
251
+ font-size:10px;
252
+ }
253
+
254
+ /* MISC HELPER STYLES */
255
+
256
+ ul.clean, ol.clean {
257
+ list-style-type: none;
258
+ padding-left: 0;
259
+ }
260
+ .caps {
261
+ font-variant:small-caps;
262
+ }
263
+ .clear {
264
+ clear:both;
265
+ }
266
+ .left{
267
+ float:left;
268
+ }
269
+ .right{
270
+ float:right;
271
+ }
272
+ .center{
273
+ text-align:center;
274
+ }
275
+ .intro {
276
+ font-size:0.833333em; /* 15px */
277
+ line-height:1.666667; /* 25px */
278
+ border:1px solid #ccc;
279
+ padding:0.5em;
280
+ font-style:italic;
281
+ color:#555;
282
+ }
283
+ a.hash,
284
+ a.hash:link,
285
+ a.hash:visited {
286
+ display:block;
287
+ float:right;
288
+ background:#fff;
289
+ font-size:0.8em;
290
+ text-decoration:none;
291
+ line-height:2;
292
+ color:#999;
293
+ }
294
+ a.hash:hover {
295
+ color:MediumOrchid;
296
+ }
297
+
298
+ /* PRINT */
299
+
300
+ @media print {
301
+ html, body, #container {
302
+ margin:0;
303
+ }
304
+ #container {
305
+ width:100%;
306
+ max-width:100%;
307
+ }
308
+ #header {
309
+ margin-top:0;
310
+ }
311
+ #header p {
312
+ display:none;
313
+ }
314
+ #footer {
315
+ display:none;
316
+ }
317
+ a, a:link, a:visited {
318
+ color:#000;
319
+ background:#fff;
320
+ text-decoration:none;
321
+ }
322
+ pre.license {
323
+ font-size:0.95em;
324
+ }
325
+ @page {
326
+ size:8.5in 11in;
327
+ }
328
+ }
329
+
330
+ /* PRETTIFICATION OF SOURCE CODE */
331
+
332
+ .str { color: #181; font-style:italic; }
333
+ .kwd { color: #369; }
334
+ .com { color: #666; }
335
+ .typ { color: #c40; }
336
+ .lit { color: #900; }
337
+ .pun { color: #000; font-weight: bold; }
338
+ .pln { color: #333; }
339
+ .tag { color: #369; font-weight: bold; }
340
+ .atn { color: #939; font-weight: bold }
341
+ .atv { color: #181; }
342
+ .dec { color: #606; }
343
+
344
+ @media print {
345
+ .str { color: #060; }
346
+ .kwd { color: #006; font-weight: bold; }
347
+ .com { color: #600; font-style: italic; }
348
+ .typ { color: #404; font-weight: bold; }
349
+ .lit { color: #044; }
350
+ .pun { color: #440; }
351
+ .pln { color: #000; }
352
+ .tag { color: #006; font-weight: bold; }
353
+ .atn { color: #404; }
354
+ .atv { color: #060; }
355
+ }
356
+
357
+ /* FUCKING IE */
358
+
359
+ * html body{width:40em}
360
+ * html div.index{width:34.5em}
361
+
362
+ /* vim: set ft=css ts=4 sw=4 noexpandtab: */