Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

yay websites

  • Loading branch information...
commit 9b66bedc2a5efa44d72be17bd0cba6aaef8ab0a0 0 parents
@jbalogh authored
1  .gitignore
@@ -0,0 +1 @@
+_site
13 _config.yml
@@ -0,0 +1,13 @@
+destination: ./_site
+auto: false
+lsi: false
+server_port: 4000
+pygments: true
+markdown: maruku
+permalink: pretty
+exclude: ["fabfile.py"]
+maruku:
+ use_tex: false
+ use_divs: false
+ png_dir: images/latex
+ png_url: /images/latex
21 _layouts/base.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>{{ page.title }}</title>
+ <link rel="stylesheet" href="/media/style.css">
+ <link rel="alternate" type="application/atom+xml"
+ href="http://feeds.feedburner.com/jbalogh"
+ title="Feed of latest posts">
+ </head>
+ <body>
+ {{ content }}
+ <!--
+ <a href="#" style="position: absolute; top: 0; right: 0" onclick="toggle()">toggle</a>
+ <script>
+ toggle = function(){ document.body.classList.toggle('grid'); return false; }
+ </script>
+ -->
+ <script defer src="/media/script.js?x"></script>
+ </body>
+</html>
15 _layouts/post.html
@@ -0,0 +1,15 @@
+---
+layout: base
+---
+<article>
+ <header>
+ <h1>{{ page.title }}</h1>
+ <div class="byline">
+ <time datetime="{{ page.date|date:"%Y-%m-%d" }}">
+ {{ page.date|date:"%B %d, %Y" }}
+ </time>
+ by <address><a href="http://jbalogh.me">Jeff Balogh</a></address>
+ </div>
+ </header>
+ {{ content }}
+</article>
45 _posts/2008-11-02-nose-test-runner-for-django.md
@@ -0,0 +1,45 @@
+---
+title: Nose Test Runner for Django
+layout: post
+---
+
+**Update: you can now find django-nose on [pypi][] and [github][] with much
+better documentation.**
+
+[pypi]: http://pypi.python.org/pypi/django-nose
+[github]: http://github.com/jbalogh/django-nose
+
+I am not a big fan of Python's `unittest` library. The Java-inspired API and
+the difficulty of running tests are too much for me to deal with. That's why I
+love [nose][]: I can use regular `assert`s (or the Pythonic helpers in
+`nose.tools`) and running all my tests is as simple as calling `nosetests` from
+the command line. On top of that, nose also supports cool plugins like
+generating coverage reports and running tests interactively, test fixtures at
+any granularity level, and simple selection of tests to run, making me a happy
+tester.
+
+Which is why I wrote a custom [test runner][tr] as soon as I started working on
+[basie][]. Django provides its own test runner framework, but it's far less
+advanced than nose.
+
+I haven't packaged it up for PyPI yet, but you can download
+[nose_runner.py][nr] from our repository. Here's the documentation:
+
+ Django test runner that invokes nose.
+
+ Usage:
+ ./manage.py test DJANGO_ARGS -- NOSE_ARGS
+
+ The 'test' argument, and any other args before '--', will not be passed to
+ nose, allowing django args and nose args to coexist.
+
+ You can use
+
+ NOSE_ARGS = ['list', 'of', 'args']
+
+ in settings.py for arguments that you always want passed to nose.
+
+[nose]: http://www.somethingaboutorange.com/mrl/projects/nose/
+[tr]: http://docs.djangoproject.com/en/dev/topics/testing/#defining-a-test-runner
+[basie]: basieproject.org
+[nr]: http://code.basieproject.org/trunk/apps/django_nose/nose_runner.py
64 _posts/2009-03-24-pyquery.md
@@ -0,0 +1,64 @@
+---
+title: "pyquery: a jquery-like library for python"
+layout: post
+---
+
+[pyquery](http://pyquery.org/) is a fantastic little library for dealing with
+XML and HTML documents. It brings the power and ease of jQuery into Python,
+letting you deal with CSS selectors and functions instead of a clunky DOM. I
+try to avoid dealing with XML as much as possible, but slinging around pyquery
+almost makes XML fun.
+
+## Building lxml
+The hardest part of working with pyquery is getting it installed. pyquery gets
+all of its XML power from [lxml][], which has a reputation for being difficult.
+[Ian Bicking][] mentioned that lxml2.2 has become much easier to install by
+providing an option to compile the troublesome C libs as static libraries,
+which has avoided any problems for me. All you need to do is define
+`STATIC_DEPS=true` in the build environment:
+
+ STATIC_DEPS=true pip install pyquery
+
+This has worked for me on OS X with `pip`, `easy_install`, `buildout`, and
+probably anything else based on `distutils`.
+
+## Web Scraping
+Web scraping is ridiculously easy with pyquery. Grabbing a [Shakespearean
+insult][3] from the web is as simple as
+
+ import pyquery
+
+ p = pyquery.PyQuery('http://www.pangloss.com/seidel/Shaker/')
+ insult = p('font').text()
+
+Finding the insult on that page is aided by the author's semantic `font` tag.
+
+## Testing
+I like to make sure that my views are working correctly, another task in which
+I'm finding pyquery indispensable. I've seen regexen used for the same task,
+but examining a real DOM is much more resilient than trying to pick out pieces
+by matching strings. Testing views is especially useful when dealing with
+template systems like Django's and Jinja's which silently hide errors instead
+of raising exceptions.
+
+ assert d('#stats').text() == '5 tests: +2 -3'
+
+I've noticed that testing the HTML in this manner has improved my semantic
+markup. Pulling out and testing pieces of the page forces me to add meaningful
+ids and classes to the elements.
+
+## Bonus
+For extra HTML goodness, the tests submit response pages to the [w3c
+Validator][4] using this [multipart form encoder][5]. Then, of course, I use
+pyquery to make sure all is well.
+
+ validator = post_multipart('validator.w3.org', '/check',
+ {'fragment': response.data})
+ assert pyquery.PyQuery(validator)('#congrats')
+
+
+[Ian Bicking]: http://blog.ianbicking.org/2008/12/10/lxml-an-underappreciated-web-scraping-library/
+[lxml]: http://codespeak.net/lxml/
+[3]: http://www.pangloss.com/seidel/Shaker/
+[4]: http://validator.w3.org/
+[5]:http://github.com/jbalogh/bosley/blob/f64cfeb739954311c36b357d657c227e6d9646a2/bosley/tests/multipart.py
37 _posts/2009-05-14-poboy.md
@@ -0,0 +1,37 @@
+---
+title: Introducing poboy
+layout: post
+---
+
+I'd be surprised if [poboy][] is useful to anyone I don't work with, but I
+wrote a README, so that should be shared with the internet.
+
+[poboy]: http://github.com/jbalogh/poboy/tree/master
+
+Finds all the gettext calls that have an inline fallback and moves that
+fallback into the messages.po file. Thus, you can use `___('msgid', 'msgstr')`
+when you're writing new code and use this script to clean up afterwards.
+
+poboy won't edit any code files. Instead, it prints out a unified diff that
+you can check for correctness and send to patch. I didn't want to deal with
+rewriting files safely.
+
+## How I use it
+
+Find all the strings that have a fallback:
+
+ poboy locale/en_US/LC_MESSAGES/messages.po --find
+
+Find the strings with a fallback that aren't already in messages.po:
+
+ poboy locale/en_US/LC_MESSAGES/messages.po -an
+
+That's `-a` for `--add` (to the .po file) and `-n` for `--dry_run`.
+
+Show the strings that will be added and the cleanup patch:
+
+ poboy locale/en_US/LC_MESSAGES/messages.po -n
+
+And the fun one, add the strings to messages.po and generate a cleanup patch:
+
+ poboy locale/en_US/LC_MESSAGES/messages.po > poboy.patch
48 _posts/2009-05-23-schematic.md
@@ -0,0 +1,48 @@
+---
+title: The worst schema versioning system, ever?
+layout: post
+---
+
+[schematic][] talks to your database over stdin on the command line. Thus, it
+supports all DBMSs that have a command line interface and doesn't care what
+programming language you worship. Win!
+
+It only looks for files in the same directory as itself so you should put this
+script, settings.py, and all migrations in the same directory.
+
+Configuration is done in `settings.py`, which should look something like:
+
+ # How to connect to the database
+ db = 'mysql --silent -p blam -D pow'
+ # The table where version info is stored.
+ table = 'schema_version'
+
+It's python so you can do whatever crazy things you want, and it's a separate
+file so you can keep local settings out of version control.
+
+Migrations are just sql in files whose names start with a number, like
+`001-adding-awesome.sql`. They're matched against `'^\d+'` so you can put
+zeros in front to keep ordering in `ls` happy, and whatever you want after the
+migration number, such as text describing the migration.
+
+[schematic][] creates a table (named in settings.py) with one column, that
+holds one row, which describes the current version of the database. Any
+migration file with a number greater than the current version will be applied
+to the database and the version tracker will be upgraded. The migration and
+version bump are performed in a transaction.
+
+The version-tracking table will initially be set to 0, so the 0th migration
+could be a script that creates all your tables (for reference). Migration
+numbers are not required to increase linearly.
+
+[schematic][] doesn't pretend to be intelligent. Running migrations manually
+without upgrading the version tracking will throw things off.
+
+Tested on sqlite any mysql.
+
+NOTE: any superfluous output, like column headers, will cause an error. On
+mysql, this is fixed by using the `--silent` parameter.
+
+Things that might be nice: downgrades, running python files.
+
+[schematic]: http://github.com/jbalogh/schematic
90 _posts/2009-10-20-djangocon-2009.md
@@ -0,0 +1,90 @@
+---
+title: Highlights from DjangoCon 2009
+layout: post
+---
+
+Long (long!) overdue, here's a bunch of links that point to the good things I
+learned at djangocon.
+
+
+## [Restful Ponies][1]
+
+* Started with a basic REST overview, gets interesting when it shows how you can
+ easily expose resources using [Piston][]
+* [django-roa][] builds on Piston to give models a basic REST API for free
+* [remoteobjects][] is an object-restational mapper that maps objects to REST
+ apis on the web. It's really cool and I'm playing with it for the new
+ Bugzilla rest view.
+
+[1]: http://immike.net/files/restful_ponies.pdf
+[Piston]: http://bitbucket.org/jespern/django-piston
+[django-roa]: http://code.welldev.org/django-roa/src/
+[remoteobjects]: http://github.com/sixapart/remoteobjects/
+
+
+## [Deploying Django][2]
+
+Talks about how they're doing "repeatable, automated, isolated" deployments
+using Python tools. Don't you wish we were rocking this on AMO?
+
+* virtualenv and pip to keep the deployment environment isolated
+* fabric to script vcs checkout and installation
+* using lightweight tags in git to mark deployment versions
+* up *and* down migrations with [South][] to stay safe
+* mod_wsgi daemon mode is preferred, fastcgi is cool too
+
+[2]: http://oebfare.com/files/DeployingDjangoDC2009.pdf
+[South]: http://south.aeracode.org/
+
+## [Scaling Django][5]
+
+Pownce was serving hundreds of request/sec, thousands of db ops/sec, it can be
+done. It's simple to do automatic caching and invalidation when your queries
+are going through the ORM, Django's signals decouple the invalidation process
+from your update code. Using multiple databases with Django is not
+straightforward, but it's getting easier with an SoC project that's ready to
+merged in.
+
+* [sqlparse][] pretty prints SQL queries
+
+[sqlparse]: http://pypi.python.org/pypi/sqlparse/0.1.1
+
+[5]: http://immike.net/files/scaling_django.pdf
+
+## [The Realtime Web][6]
+
+Showed how they created an IRC client in the browser over comet with Django on
+the backend. The browser and the app keep "persistent" connections to an
+[orbited][] server that handles all the messy details so the app can pretend
+it's really connected directly to the browser.
+
+This coincided with the release of FriendFeed's [Tornado][] web server, which
+led to an interesting focus on async during the conference.
+
+[orbited]: http://orbited.org/
+
+[Tornado]: http://www.tornadoweb.org/
+
+[6]: http://www.slideshare.net/err/the-realtime-web-and-other-buzzwords
+
+## [Using Django in Non-Standard Ways][3]
+
+Covers a lot of little hurdles that people might consider show-stoppers when
+using Django, how to overcome them. WSGI middleware is fun:
+
+* repoze.bitblt: automatically scales images
+* repoze.squeeze: Merges JS/CSS automatically based on statistical analysis
+* repoze.profile: Aggregates Python profiling data across all requests, and
+ provides an html frontend for viewing the data
+* repoze.slicer: extract/filter pieces of an html response
+
+[3]: http://media.eflorenzano.com/dropbox/UsingDjangoInNonStandardWays.pdf
+
+
+## [Pinax Tutorial][4]
+
+Pinax tries to be a collection of reusable apps that work well together, but it
+looks like you spend more time trying to configure things than actually making
+useful apps.
+
+[4]: http://www.slideshare.net/pydanny/pinax-tutorial-090909
101 _posts/2010-02-09-cache-machine.md
@@ -0,0 +1,101 @@
+---
+title: "Cache Machine: Automatic caching for your Django models"
+layout: post
+---
+
+[Cache Machine][1] hooks into Django's ORM to provide easy object caching and
+invalidation.
+
+[1]: http://github.com/jbalogh/django-cache-machine
+
+One of our primary goals with the rewrite of
+[addons.mozilla.org](https://addons.mozilla.org) was to improve our cache
+management. Large sites like <abbr title="addons.mozilla.org">AMO</abbr> rely
+on layers of caching to stay afloat, and caching database queries in memcached
+is one of our favorite tools.
+
+AMO heavily favors reads over writes, so we have great cache performance; the
+hit rate ranges from 90%-98%. However, once something is in the cache, it's
+stuck there until timeout (60 minutes). Combined with front-end caching, this
+can mean it's a couple of hours before add-on developers see their changes roll
+out to the site. We don't like that.
+
+For [zamboni](http://github.com/jbalogh/zamboni), our Django-based rewrite,
+seamless object caching and invalidation was my first project. Today we
+released [Cache Machine][1] as a drop-in library for use in any Django
+application. The package is available on [pypi][] and the code is on
+[github][1].
+
+[pypi]: http://pypi.python.org/pypi/django-cache-machine
+
+
+## Usage
+
+Here's a cache-enabled model:
+
+{% highlight python %}
+from django.db import models
+
+import caching.base
+
+class Zomg(caching.base.CachingMixin, models.Model):
+ val = models.IntegerField()
+
+ objects = caching.base.CachingManager()
+{% endhighlight %}
+
+The first step is to inherit from [``CachingMixin``][2]. This mixin gives your
+model ``post_sync`` and ``post_delete`` signal handlers that will flush the
+object from cache. It also adds a ``cache_key`` property that helps invalidate
+the object properly.
+
+Then you replace the default manager with [``CachingManager``][3]. Instead of
+a normal ``QuerySet``, this manager returns ``CachingQuerySets`` which try to
+pull objects from cache before performing a database lookup.
+
+
+## How it works
+
+Cache Machine knows how to cache normal ``QuerySets`` and ``RawQuerySets``.
+Each ``QuerySet`` is keyed by the active locale and the SQL of the underlying
+query. The ``CachingQuerySet`` wraps around ``Queryset.iterator()`` to check
+cache before hitting the database.
+
+Invalidation is the interesting part. As we iterate through a set of objects
+in a database result, we create a "flush list" for each object. The flush list
+maps each object to a list of cached queries it's a member of. When an object
+is invalidated in the ``post_sync`` signal, all of the queries it was a part of
+are immediately invalidated.
+
+Parent and child foreign-key relationships are also tracked in the flush lists.
+If a parent object changes, its flush list will be invalidated along with all
+children that point to it, and vice versa.
+
+
+## Issues
+
+Only the ``memcached`` and ``locmem`` backends are supported. Cache Machine
+relies on infinite cache timeouts for storing flush lists, but none of Django's
+builtin backends support this (even though the memcached server does). We wrap
+the memcached and locmem backends to fix the infinite timeout issue, but file
+and database backends aren't implemented since they're not useful to us.
+
+Cache Machine does not cache ``values()`` and ``values_list()`` calls. Since
+these methods don't return full objects, we can't know how to invalidate them
+properly. They could be overridden to do normal lookups and then pull out the
+results, but I haven't gotten around to that yet.
+
+``count()`` queries will not be cached. These can't be invalidated
+efficiently. I recommend denormalizing your tables and adding a count field if
+you need to access it often. *Update: limited count caching was enabled in
+[this commit][cache-count].*
+
+[cache-count]: http://github.com/jbalogh/django-cache-machine/commit/c1e871f4d7
+
+Cache Machine has a few ``log.debug`` calls in its caching and invalidation
+internals. These work fine with zamboni, since we set up our logging on
+startup. I don't know if these calls will be problematic without or logging
+config. Let me know.
+
+[2]: http://jbalogh.me/projects/cache-machine/#caching.base.CachingMixin
+[3]: http://jbalogh.me/projects/cache-machine/#caching.base.CachingManager
27 atom.xml
@@ -0,0 +1,27 @@
+---
+layout: nil
+---
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+ <title>Jeff Balogh</title>
+ <link href="http://jbalogh.me/atom.xml" rel="self"/>
+ <link href="http://jbalogh.me/"/>
+ <updated>{{ site.time | date_to_xmlschema }}</updated>
+ <id>http://jbalogh.me/</id>
+ <author>
+ <name>Jeff Balogh</name>
+ <email>contact@jeffbalogh.org</email>
+ </author>
+
+ {% for post in site.posts %}
+ <entry>
+ <title>{{ post.title }}</title>
+ <link href="http://jbalogh.me{{ post.url }}"/>
+ <updated>{{ post.date | date_to_xmlschema }}</updated>
+ <id>http://jbalogh.me{{ post.id }}</id>
+ <content type="html">{{ post.content | xml_escape }}</content>
+ </entry>
+ {% endfor %}
+
+</feed>
10 fabfile.py
@@ -0,0 +1,10 @@
+from fabric.api import run, local, env
+from fabric.contrib.project import rsync_project
+
+env.user = 'jbalogh'
+env.hosts = ['jbalogh.me']
+
+def up():
+ local('rm -rf _site')
+ local('jekyll')
+ rsync_project('w', '_site/', exclude='projects', delete=True)
BIN  favicon.ico
Binary file not shown
30 index.html
@@ -0,0 +1,30 @@
+---
+layout: base
+title: Jeff Balogh
+---
+
+<section id="about">
+ <h1>Jeff Balogh</h1>
+ <p>
+ I'm a web developer at Mozilla.<br>
+ All of my code is on <a href="http://github.com/jbalogh">github</a> and
+ sometimes I remember to update
+ <a href="http://twitter.com/jeffbalogh">twitter</a>.
+ </p>
+</section>
+<section id="posts">
+ <h1>Writing</h1>
+ <ul>
+ {% for post in site.posts %}
+ <li>
+ <time datetime="{{ post.date|date:"%Y-%m-%d" }}">
+ {{ post.date|date:"%b %d %Y" }}
+ </time>
+ <a href="{{ post.url }}">{{ post.title }}</a>
+ </li>
+ {% endfor %}
+ </ul>
+</section>
+<section id="projects">
+ <h1>Projects</h1>
+</section>
BIN  media/Calluna-Regular.otf
Binary file not shown
BIN  media/DroidSans.ttf
Binary file not shown
BIN  media/Inconsolata.otf
Binary file not shown
BIN  media/baseline.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 media/script.js
@@ -0,0 +1,43 @@
+/** Google Analytics **/
+var _gaq = _gaq || [];
+_gaq.push(['_setAccount', 'UA-12894354-1']);
+_gaq.push(['_trackPageview']);
+
+var makeScript = function(src) {
+ var s = document.createElement('script');
+ s.type = 'text/javascript';
+ s.async = true;
+ s.src = src;
+ document.body.appendChild(s);
+};
+
+var src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+makeScript(src);
+
+
+/** Github projects **/
+var names = ['zamboni', 'django-nose', 'django-cache-machine',
+ 'django-multidb-router', 'jingo', 'schematic',
+ 'jetpacks', 'check'];
+var project_el = document.querySelector('#projects')
+if (project_el) {
+ var github = 'http://github.com/api/v1/json/jbalogh/';
+ var projects = {};
+
+ var loadProjects = function(json) {
+ var repos = json.user.repositories;
+ for (var i in repos) {
+ repo = repos[i];
+ projects[repo.name] = repo;
+ }
+ dts = []
+ for (var i in names) {
+ var name = names[i],
+ p = projects[name],
+ dt = '<dt><a href="' + p.url + '">' + name + '</a></dt>';
+ dts.push(dt + '<dd>' + p.description + '</dd>');
+ }
+ project_el.innerHTML += '<dl>' + dts.join('') + '</dl>';
+ };
+ makeScript(github + '?callback=loadProjects');
+}
271 media/style.css
@@ -0,0 +1,271 @@
+/* http://meyerweb.com/eric/tools/css/reset/ */
+/* v1.0 | 20080212 */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ font-size: 100%;
+ vertical-align: baseline;
+ background: transparent;
+}
+ol, ul {
+ list-style-type: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+
+/* remember to define focus styles! */
+:focus {
+ outline: 0;
+}
+
+/* remember to highlight inserts somehow! */
+ins {
+ text-decoration: none;
+}
+del {
+ text-decoration: line-through;
+}
+
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/** Pygments: monokai **/
+.hll { background-color: #49483e }
+.c { color: #75715e } /* Comment */
+.err { color: #960050; background-color: #1e0010 } /* Error */
+.k { color: #66d9ef } /* Keyword */
+.l { color: #ae81ff } /* Literal */
+.n { color: #f8f8f2 } /* Name */
+.o { color: #f92672 } /* Operator */
+.p { color: #f8f8f2 } /* Punctuation */
+.cm { color: #75715e } /* Comment.Multiline */
+.cp { color: #75715e } /* Comment.Preproc */
+.c1 { color: #75715e } /* Comment.Single */
+.cs { color: #75715e } /* Comment.Special */
+.ge { font-style: italic } /* Generic.Emph */
+.gs { font-weight: bold } /* Generic.Strong */
+.kc { color: #66d9ef } /* Keyword.Constant */
+.kd { color: #66d9ef } /* Keyword.Declaration */
+.kn { color: #f92672 } /* Keyword.Namespace */
+.kp { color: #66d9ef } /* Keyword.Pseudo */
+.kr { color: #66d9ef } /* Keyword.Reserved */
+.kt { color: #66d9ef } /* Keyword.Type */
+.ld { color: #e6db74 } /* Literal.Date */
+.m { color: #ae81ff } /* Literal.Number */
+.s { color: #e6db74 } /* Literal.String */
+.na { color: #a6e22e } /* Name.Attribute */
+.nb { color: #f8f8f2 } /* Name.Builtin */
+.nc { color: #a6e22e } /* Name.Class */
+.no { color: #66d9ef } /* Name.Constant */
+.nd { color: #a6e22e } /* Name.Decorator */
+.ni { color: #f8f8f2 } /* Name.Entity */
+.ne { color: #a6e22e } /* Name.Exception */
+.nf { color: #a6e22e } /* Name.Function */
+.nl { color: #f8f8f2 } /* Name.Label */
+.nn { color: #f8f8f2 } /* Name.Namespace */
+.nx { color: #a6e22e } /* Name.Other */
+.py { color: #f8f8f2 } /* Name.Property */
+.nt { color: #f92672 } /* Name.Tag */
+.nv { color: #f8f8f2 } /* Name.Variable */
+.ow { color: #f92672 } /* Operator.Word */
+.w { color: #f8f8f2 } /* Text.Whitespace */
+.mf { color: #ae81ff } /* Literal.Number.Float */
+.mh { color: #ae81ff } /* Literal.Number.Hex */
+.mi { color: #ae81ff } /* Literal.Number.Integer */
+.mo { color: #ae81ff } /* Literal.Number.Oct */
+.sb { color: #e6db74 } /* Literal.String.Backtick */
+.sc { color: #e6db74 } /* Literal.String.Char */
+.sd { color: #e6db74 } /* Literal.String.Doc */
+.s2 { color: #e6db74 } /* Literal.String.Double */
+.se { color: #ae81ff } /* Literal.String.Escape */
+.sh { color: #e6db74 } /* Literal.String.Heredoc */
+.si { color: #e6db74 } /* Literal.String.Interpol */
+.sx { color: #e6db74 } /* Literal.String.Other */
+.sr { color: #e6db74 } /* Literal.String.Regex */
+.s1 { color: #e6db74 } /* Literal.String.Single */
+.ss { color: #e6db74 } /* Literal.String.Symbol */
+.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
+.vc { color: #f8f8f2 } /* Name.Variable.Class */
+.vg { color: #f8f8f2 } /* Name.Variable.Global */
+.vi { color: #f8f8f2 } /* Name.Variable.Instance */
+.il { color: #ae81ff } /* Literal.Number.Integer.Long */
+
+
+/** Normal stying. **/
+
+@font-face {
+ font-family: "Calluna";
+ src: url(Calluna-Regular.otf);
+}
+
+@font-face {
+ font-family: "Inconsolata";
+ src: url(Inconsolata.otf);
+}
+
+body {
+ font-weight: normal;
+ color: #727373;
+ color: #483318;
+ width: 40em;
+ margin: 20px auto 0;
+ font-size: 18px;
+ line-height: 24px;
+ font-family: Calluna, Georgia, serif;
+}
+
+body.grid {
+ background-image: url(baseline.gif);
+}
+
+/** Headings **/
+
+h1, h2, h3, h4, h5, h6 {
+ font-weight: normal;
+ font-family: "Helvetica Neue", Helvetica, sans-serif;
+}
+
+section, header {
+ display: block;
+}
+
+address {
+ display: inline;
+ font-style: normal;
+}
+
+/** Articles & Sections **/
+
+article > header {
+ margin-bottom: 24px;
+}
+
+section h1,
+article header h1 {
+ font-size: 36px;
+ font-family: Calluna, Georgia, serif;
+ line-height: 36px;
+ color: #332411;
+}
+
+section h1 {
+ margin-bottom: 18px;
+}
+
+section {
+ margin-bottom: 18px;
+}
+
+article header h1 + .byline {
+ line-height: 18px;
+ font-size: 14px;
+ color: #555;
+}
+
+article h2 {
+ line-height: 28px;
+ font-size: 28px;
+ margin-bottom: 8px;
+ margin-top: 12px;
+}
+
+/** Links **/
+
+a {
+ color: #146894;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a:visited {
+ color: #441d7b;
+}
+
+/** Lists **/
+
+ul {
+ text-indent: -6px;
+}
+
+ul li:before {
+ content: "";
+ font-size: 10px;
+ line-height: 10px;
+}
+
+p + ul {
+ margin: 12px 0;
+}
+
+/** Misc **/
+
+p + p {
+ margin-top: 24px;
+}
+
+code {
+ font-family: Inconsolata, monospace;
+}
+
+pre {
+ margin: 8px 0 8px 2em;
+ font-size: 14px;
+ line-height: 16px;
+ margin-left: 2em;
+}
+
+.highlight {
+ margin: 6px 0;
+ padding: 6px 0;
+ background: #333;
+ -moz-border-radius: 20px;
+ -webkit-border-radius: 20px;
+ border-radius: 20px;
+}
+
+/** Homepage **/
+
+#posts ul {
+ text-indent: 0;
+}
+
+#posts ul li:before {
+ content: none;
+}
+
+#projects dt {
+ clear: both;
+ padding-right: 4px;
+}
+
+#projects dt:after {
+ content: ":";
+}
+
+#projects dt,
+#projects dd {
+ float: left;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.