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.
- data/CHANGES +27 -0
- data/COPYING +18 -0
- data/README +96 -0
- data/Rakefile +144 -0
- data/TODO +40 -0
- data/doc/configuration.markdown +224 -0
- data/doc/events.dot +27 -0
- data/doc/faq.markdown +133 -0
- data/doc/index.markdown +113 -0
- data/doc/layout.html.erb +33 -0
- data/doc/license.markdown +24 -0
- data/doc/rack-cache.css +362 -0
- data/doc/storage.markdown +162 -0
- data/lib/rack/cache.rb +51 -0
- data/lib/rack/cache/config.rb +65 -0
- data/lib/rack/cache/config/busters.rb +16 -0
- data/lib/rack/cache/config/default.rb +134 -0
- data/lib/rack/cache/config/no-cache.rb +13 -0
- data/lib/rack/cache/context.rb +95 -0
- data/lib/rack/cache/core.rb +271 -0
- data/lib/rack/cache/entitystore.rb +224 -0
- data/lib/rack/cache/headers.rb +237 -0
- data/lib/rack/cache/metastore.rb +309 -0
- data/lib/rack/cache/options.rb +119 -0
- data/lib/rack/cache/request.rb +37 -0
- data/lib/rack/cache/response.rb +76 -0
- data/lib/rack/cache/storage.rb +50 -0
- data/lib/rack/utils/environment_headers.rb +78 -0
- data/rack-cache.gemspec +74 -0
- data/test/cache_test.rb +35 -0
- data/test/config_test.rb +66 -0
- data/test/context_test.rb +465 -0
- data/test/core_test.rb +84 -0
- data/test/entitystore_test.rb +176 -0
- data/test/environment_headers_test.rb +71 -0
- data/test/headers_test.rb +215 -0
- data/test/logging_test.rb +45 -0
- data/test/metastore_test.rb +210 -0
- data/test/options_test.rb +64 -0
- data/test/pony.jpg +0 -0
- data/test/response_test.rb +37 -0
- data/test/spec_setup.rb +189 -0
- data/test/storage_test.rb +94 -0
- 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.
|
data/doc/index.markdown
ADDED
@@ -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 © 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"
|
data/doc/layout.html.erb
ADDED
@@ -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">©</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 © 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>
|
data/doc/rack-cache.css
ADDED
@@ -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: */
|