aboutsummaryrefslogtreecommitdiffstats
path: root/ryuslash
diff options
context:
space:
mode:
authorGravatar Tom Willemse2013-05-09 20:07:49 +0200
committerGravatar Tom Willemse2013-05-09 20:07:49 +0200
commit15c5869b54e9a770b9abbeab1e990b713cdb1b3b (patch)
tree4aa805a44e8da93f4b0698520f16096d216d8ec3 /ryuslash
parent5f7df695ac6dd9ccc5444a8fc20fa8d97196953e (diff)
downloadryuslash.org-15c5869b54e9a770b9abbeab1e990b713cdb1b3b.tar.gz
ryuslash.org-15c5869b54e9a770b9abbeab1e990b713cdb1b3b.zip
Update for django 1.4
Diffstat (limited to 'ryuslash')
-rw-r--r--ryuslash/__init__.py0
-rw-r--r--ryuslash/aggregator/README.org5
-rw-r--r--ryuslash/aggregator/__init__.py0
-rw-r--r--ryuslash/aggregator/feeds.py23
-rw-r--r--ryuslash/aggregator/management/__init__.py0
-rw-r--r--ryuslash/aggregator/management/commands/__init__.py0
-rw-r--r--ryuslash/aggregator/management/commands/loadfeeds.py101
-rw-r--r--ryuslash/aggregator/migrations/0001_initial.py40
-rw-r--r--ryuslash/aggregator/migrations/__init__.py0
-rw-r--r--ryuslash/aggregator/models.py14
-rw-r--r--ryuslash/aggregator/templates/aggregator/base.html46
-rw-r--r--ryuslash/aggregator/templates/aggregator/posts.html43
-rw-r--r--ryuslash/aggregator/templatetags/__init__.py0
-rw-r--r--ryuslash/aggregator/templatetags/posts_extras.py20
-rw-r--r--ryuslash/aggregator/views.py22
-rw-r--r--ryuslash/local_settings.py.example42
-rw-r--r--ryuslash/settings.py106
-rw-r--r--ryuslash/static/favicon.pngbin0 -> 1128 bytes
-rw-r--r--ryuslash/static/images/logos/.gitignore2
-rw-r--r--ryuslash/static/logo.pngbin0 -> 15931 bytes
-rw-r--r--ryuslash/static/main.css272
-rw-r--r--ryuslash/urls.py11
22 files changed, 747 insertions, 0 deletions
diff --git a/ryuslash/__init__.py b/ryuslash/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/__init__.py
diff --git a/ryuslash/aggregator/README.org b/ryuslash/aggregator/README.org
new file mode 100644
index 0000000..1bca9e7
--- /dev/null
+++ b/ryuslash/aggregator/README.org
@@ -0,0 +1,5 @@
+* aggregator
+
+ A simple django app that collects posts from specified feeds. It
+ keeps track of which was last updated when and copies the data to
+ its own tables.
diff --git a/ryuslash/aggregator/__init__.py b/ryuslash/aggregator/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/aggregator/__init__.py
diff --git a/ryuslash/aggregator/feeds.py b/ryuslash/aggregator/feeds.py
new file mode 100644
index 0000000..75e5d4f
--- /dev/null
+++ b/ryuslash/aggregator/feeds.py
@@ -0,0 +1,23 @@
+from django.contrib.syndication.views import Feed
+
+from .models import Post
+
+class LatestPostsFeed(Feed):
+ title = "ryuslash's RSS feed"
+ link = "/"
+ description = "Updates by ryuslash"
+
+ def items(self):
+ return Post.objects.all()[:20]
+
+ def item_title(self, item):
+ return item.title
+
+ def item_description(self, item):
+ return item.body
+
+ def item_link(self, item):
+ return "/post/%d/" % item.pk
+
+ def item_pubdate(self, item):
+ return item.updated
diff --git a/ryuslash/aggregator/management/__init__.py b/ryuslash/aggregator/management/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/aggregator/management/__init__.py
diff --git a/ryuslash/aggregator/management/commands/__init__.py b/ryuslash/aggregator/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/aggregator/management/commands/__init__.py
diff --git a/ryuslash/aggregator/management/commands/loadfeeds.py b/ryuslash/aggregator/management/commands/loadfeeds.py
new file mode 100644
index 0000000..f826312
--- /dev/null
+++ b/ryuslash/aggregator/management/commands/loadfeeds.py
@@ -0,0 +1,101 @@
+import feedparser
+import datetime
+import markdown
+import re
+import os
+import urllib2
+
+from django.core.management.base import BaseCommand
+
+from aggregator.models import Post
+import settings
+
+class Command(BaseCommand):
+ help = "Load data from saved feeds."
+
+ def prep_feedname(self, value):
+ value = re.sub('[^\w\s-]', '', value).strip().lower()
+ return re.sub('[-\s]+', '-', value)
+
+ def get_ext(self, options):
+ if 'favicon_ext' in options.keys():
+ return options['favicon_ext']
+ else:
+ return 'ico'
+
+ def get_logopath(self, feedname, options):
+ ext = self.get_ext(options)
+ filename = self.prep_feedname(feedname) + '.' + ext
+ basedir = os.path.dirname(os.path.abspath(settings.__file__))
+ return os.path.join(basedir, 'static/images/logos', filename)
+
+ def have_logo(self, feedname, options):
+ logopath = self.get_logopath(feedname, options)
+ return os.path.exists(logopath)
+
+ def save_logo(self, feedname, options):
+ ext = self.get_ext(options)
+ url = options['base_url'] + '/favicon.' + ext
+
+ try:
+ logo = urllib2.urlopen(url)
+ except:
+ return
+
+ save = open(self.get_logopath(feedname, options), 'w')
+
+ save.write(logo.read())
+ save.close()
+ logo.close()
+
+ def construct_feed_url(self, feed):
+ return feed['base_url'] + feed['feed_url']
+
+ def handle(self, *args, **kwargs):
+ for feedname, feedoptions in settings.FEEDS.iteritems():
+ parsed = \
+ feedparser.parse(self.construct_feed_url(feedoptions))
+ icon = self.prep_feedname(feedname) + '.' \
+ + self.get_ext(feedoptions)
+ newcount = 0
+
+ if not self.have_logo(feedname, feedoptions):
+ self.save_logo(feedname, feedoptions)
+
+ for entry in parsed.entries:
+ if Post.objects.filter(post_id=entry.id).exists():
+ continue
+
+ dt = entry.updated_parsed \
+ or entry.published_parsed
+
+ if dt:
+ updated = datetime.datetime(
+ dt.tm_year, dt.tm_mon, dt.tm_mday,
+ dt.tm_hour, dt.tm_min, dt.tm_sec)
+ else:
+ updated = datetime.datetime.now()
+
+ if 'content' in entry.keys():
+ content = entry.content[0]['value']
+ else:
+ content = entry.summary
+
+ if feedoptions['markdown']:
+ content = markdown.markdown(content)
+
+ if feedoptions.get('nl2br'):
+ content = re.sub('\n', '</br>\n', content)
+
+ post = Post(post_id=entry.id,
+ title=entry.title,
+ category=feedoptions['category'],
+ link=entry.link,
+ updated=updated,
+ icon=icon,
+ content=content)
+
+ post.save()
+ newcount += 1
+
+ print 'Grabbed %d new feeds from %s' % (newcount, feedname)
diff --git a/ryuslash/aggregator/migrations/0001_initial.py b/ryuslash/aggregator/migrations/0001_initial.py
new file mode 100644
index 0000000..550a389
--- /dev/null
+++ b/ryuslash/aggregator/migrations/0001_initial.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'Post'
+ db.create_table('aggregator_post', (
+ ('post_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255, primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=500)),
+ ('category', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('link', self.gf('django.db.models.fields.URLField')(max_length=255)),
+ ('updated', self.gf('django.db.models.fields.DateTimeField')()),
+ ('content', self.gf('django.db.models.fields.TextField')()),
+ ('icon', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ))
+ db.send_create_signal('aggregator', ['Post'])
+
+ def backwards(self, orm):
+ # Deleting model 'Post'
+ db.delete_table('aggregator_post')
+
+ models = {
+ 'aggregator.post': {
+ 'Meta': {'ordering': "['-updated']", 'object_name': 'Post'},
+ 'category': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'icon': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'link': ('django.db.models.fields.URLField', [], {'max_length': '255'}),
+ 'post_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
+ 'updated': ('django.db.models.fields.DateTimeField', [], {})
+ }
+ }
+
+ complete_apps = ['aggregator'] \ No newline at end of file
diff --git a/ryuslash/aggregator/migrations/__init__.py b/ryuslash/aggregator/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/aggregator/migrations/__init__.py
diff --git a/ryuslash/aggregator/models.py b/ryuslash/aggregator/models.py
new file mode 100644
index 0000000..34fb5a3
--- /dev/null
+++ b/ryuslash/aggregator/models.py
@@ -0,0 +1,14 @@
+from django.db import models
+
+class Post(models.Model):
+ post_id = models.CharField(max_length=255, unique=True,
+ primary_key=True)
+ title = models.CharField(max_length=500)
+ category = models.CharField(max_length=255)
+ link = models.URLField(max_length=255)
+ updated = models.DateTimeField()
+ content = models.TextField()
+ icon = models.CharField(max_length=255)
+
+ class Meta:
+ ordering = [ '-updated' ]
diff --git a/ryuslash/aggregator/templates/aggregator/base.html b/ryuslash/aggregator/templates/aggregator/base.html
new file mode 100644
index 0000000..215ec7e
--- /dev/null
+++ b/ryuslash/aggregator/templates/aggregator/base.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+
+<html lang="en">
+ <head>
+ <meta charset="utf-8" />
+ <title>ryuslash</title>
+ <link href="/static/main.css" rel="stylesheet" />
+ <link rel="shortcut icon" href="/static/favicon.png" />
+ {% block head %}{% endblock %}
+ </head>
+ <body>
+
+ <header>
+ <img src="/static/logo.png" alt="ryuslash.org" title="ryuslash.org"/>
+ <h1>
+ <a href="http://ryuslash.org">
+ <span id="logo-blue">ryu</span><span id="logo-orange">slash</span>
+ </a>
+ </h1>
+
+ <nav>
+ <ul>
+ {% if category == 'post' %}
+ <li class="selected top">
+ {% else %}
+ <li class="top">
+ {% endif %}
+ <a href="/">posts</a>
+ </li>
+
+ {% if category == 'activity' %}
+ <li class="selected bottom">
+ {% else %}
+ <li class="bottom">
+ {% endif %}
+ <a href="/activity/">activities</a>
+ </li>
+ </ul>
+ </nav>
+ </header>
+
+ <section class="content">
+ {% block content %}{% endblock %}
+ </div>
+ </body>
+</html>
diff --git a/ryuslash/aggregator/templates/aggregator/posts.html b/ryuslash/aggregator/templates/aggregator/posts.html
new file mode 100644
index 0000000..b70cb0d
--- /dev/null
+++ b/ryuslash/aggregator/templates/aggregator/posts.html
@@ -0,0 +1,43 @@
+{% extends "aggregator/base.html" %}
+{% load posts_extras %}
+
+{% block head %}
+<link href="/feeds/posts/" rel="alternate" type="application/rss+xml"
+ title="All posts" />
+{% endblock %}
+
+{% block content %}
+ {% for post in list.object_list %}
+ <article class="post">
+ (<span class="keyword">defpost</span>
+ <a href="{{ post.link }}"
+ class="variable-name">{{ post.title|slugify|nameless|truncate:48 }}</a>
+ (<img src="/static/images/logos/{{ post.icon }}" width="16"
+ height="16"/>)
+ <div class="doc">
+ {% autoescape off %}{{ post.content }}{% endautoescape %}
+ </div>
+ <span class="string">&quot;{{ post.updated }}&quot;</span>)
+ </article>
+ {% endfor %}
+
+<div id="pager">
+ {% if list.has_previous %}
+ <span class="nav-prev">
+ <a href="/{{ category }}/{{ list.previous_page_number }}/"
+ id="previous">[previous]</a>
+ </span>
+ {% endif %}
+
+ <span id="current">
+ {{ list.number }} / {{ list.paginator.num_pages }}
+ </span>
+
+ {% if list.has_next %}
+ <span class="nav-next">
+ <a href="/{{ category }}/{{ list.next_page_number }}/"
+ id="next">[next]</a>
+ </span>
+ {% endif %}
+</div>
+{% endblock %}
diff --git a/ryuslash/aggregator/templatetags/__init__.py b/ryuslash/aggregator/templatetags/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ryuslash/aggregator/templatetags/__init__.py
diff --git a/ryuslash/aggregator/templatetags/posts_extras.py b/ryuslash/aggregator/templatetags/posts_extras.py
new file mode 100644
index 0000000..64718a2
--- /dev/null
+++ b/ryuslash/aggregator/templatetags/posts_extras.py
@@ -0,0 +1,20 @@
+import re
+
+from django import template
+from django.template.defaultfilters import stringfilter
+
+register = template.Library()
+
+@stringfilter
+def nameless(value):
+ return re.sub(r'(^|by[- ])(ryuslash|tom)[- ]?', '', value)
+
+@stringfilter
+def truncate(value, length):
+ if len(value) > length:
+ value = value[:length-3] + '...'
+
+ return value
+
+register.filter('nameless', nameless)
+register.filter('truncate', truncate)
diff --git a/ryuslash/aggregator/views.py b/ryuslash/aggregator/views.py
new file mode 100644
index 0000000..bb3c1b7
--- /dev/null
+++ b/ryuslash/aggregator/views.py
@@ -0,0 +1,22 @@
+from django.core.paginator import Paginator, InvalidPage, EmptyPage
+from django.http import Http404
+from django.shortcuts import render
+
+from .models import Post
+
+def posts(request, cat, page=1):
+ category = cat or 'post'
+ queryset = Post.objects.filter(category=category)
+ paginator = Paginator(queryset, 20)
+
+ if page == None:
+ page = 1
+
+ try:
+ object_list = paginator.page(page)
+ except (EmptyPage, InvalidPage):
+ raise Http404
+
+ return render(request, 'aggregator/posts.html',
+ { 'list': object_list,
+ 'category': category })
diff --git a/ryuslash/local_settings.py.example b/ryuslash/local_settings.py.example
new file mode 100644
index 0000000..9247eba
--- /dev/null
+++ b/ryuslash/local_settings.py.example
@@ -0,0 +1,42 @@
+import os
+import sys
+
+DEPLOY_PATH = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, DEPLOY_PATH)
+sys.path.insert(0, "/home/ryuslash/.python/lib/python2.6/site-packages/South-0.7.3-py2.6.egg")
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ # ('Your Name', 'your_email@example.com'),
+)
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': 'test.sqlite', # Or path to database file if using sqlite3.
+ 'USER': '', # Not used with sqlite3.
+ 'PASSWORD': '', # Not used with sqlite3.
+ 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# On Unix systems, a value of None will cause Django to use the same
+# timezone as the operating system.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'Europe/Brussels'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = ''
+
+FEEDS = {'Diaspora*':
+ { 'base_url': 'http://diasp.org/',
+ 'feed_url': 'public/someuser.atom',
+ 'markdown': True,
+ 'category': 'post' }}
diff --git a/ryuslash/settings.py b/ryuslash/settings.py
new file mode 100644
index 0000000..c5eecee
--- /dev/null
+++ b/ryuslash/settings.py
@@ -0,0 +1,106 @@
+# Django settings for ryuslash_org project.
+from local_settings import *
+
+MANAGERS = ADMINS
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# If you set this to False, Django will not format dates, numbers and
+# calendars according to the current locale
+USE_L10N = True
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/home/media/media.lawrence.com/media/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash.
+# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
+MEDIA_URL = ''
+
+# Absolute path to the directory static files should be collected to.
+# Don't put anything in this directory yourself; store your static files
+# in apps' "static/" subdirectories and in STATICFILES_DIRS.
+# Example: "/home/media/media.lawrence.com/static/"
+STATIC_ROOT = ''
+
+# URL prefix for static files.
+# Example: "http://media.lawrence.com/static/"
+STATIC_URL = '/static/'
+
+# Additional locations of static files
+STATICFILES_DIRS = [ '%s/static' % DEPLOY_PATH ]
+
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+)
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+# 'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+)
+
+ROOT_URLCONF = 'ryuslash.urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+INSTALLED_APPS = ('django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.staticfiles',
+ 'aggregator',
+ 'south')
+
+# A sample logging configuration. The only tangible logging
+# performed by this configuration is to send an email to
+# the site admins on every HTTP 500 error.
+# See http://docs.djangoproject.com/en/dev/topics/logging for
+# more details on how to customize your logging configuration.
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'filters': {
+ 'require_debug_false': {
+ '()': 'django.utils.log.RequireDebugFalse'
+ }
+ },
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['require_debug_false'],
+ 'class': 'django.utils.log.AdminEmailHandler'
+ }
+ },
+ 'loggers': {
+ 'django.request': {
+ 'handlers': ['mail_admins'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ }
+}
diff --git a/ryuslash/static/favicon.png b/ryuslash/static/favicon.png
new file mode 100644
index 0000000..66fc2e4
--- /dev/null
+++ b/ryuslash/static/favicon.png
Binary files differ
diff --git a/ryuslash/static/images/logos/.gitignore b/ryuslash/static/images/logos/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/ryuslash/static/images/logos/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/ryuslash/static/logo.png b/ryuslash/static/logo.png
new file mode 100644
index 0000000..a451578
--- /dev/null
+++ b/ryuslash/static/logo.png
Binary files differ
diff --git a/ryuslash/static/main.css b/ryuslash/static/main.css
new file mode 100644
index 0000000..4c8a460
--- /dev/null
+++ b/ryuslash/static/main.css
@@ -0,0 +1,272 @@
+* {
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+
+a {
+ text-decoration: none;
+ color: orange;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+body {
+ background-color: #252a2b;
+ color: #ffffff;
+ font-family: "DejaVu Sans", sans-serif;
+ padding-left: 10px;
+}
+
+body > header {
+ float: left;
+ position: fixed;
+}
+
+body > header > h1 {
+ font-size: 20px;
+}
+
+body > header > h1 > a:hover {
+ text-decoration: none;
+}
+
+body > header > nav > ul {
+ list-style-type: none;
+ margin-top: 5px;
+}
+
+body > header > nav > ul > li {
+ margin: 0 3px;
+ font-weight: bold;
+ color: white;
+ border-width: 0 1px 0 1px;
+ border-style: solid;
+ border-color: #808080;
+}
+
+body > header > nav > ul > li:hover {
+ background-color: #181818;
+ border-color: #404040;
+}
+
+body > header > nav > ul > li.top {
+ border-top-width: 1px;
+ border-radius: 4px 4px 0 0;
+}
+
+body > header > nav > ul > li.bottom {
+ border-bottom-width: 1px;
+ border-radius: 0 0 4px 4px;
+}
+
+body > header > nav > ul > li > a {
+ padding: 3px 6px 3px 6px;
+ display: block;
+}
+
+body > header > nav > ul > li > a:hover {
+ text-decoration: none;
+ color: orangered;
+}
+
+pre {
+ margin: 20px 0 20px 40px;
+ font-family: "DejaVu Sans Mono", mono;
+ background-color: #181818;
+ border-radius: 10px;
+ padding: 5px;
+ color: #eeeeec;
+}
+
+code {
+ font-family: "DejaVu Sans Mono", mono;
+ background-color: #181818;
+ padding: 1px 3px;
+ border-radius: 5px;
+ margin: 0 2px;
+ color: #eeeeec;
+}
+
+article ul {
+ margin-left: 20px;
+}
+
+article img {
+ vertical-align: middle;
+}
+
+#logo-blue {
+ color: orangered;
+ position: relative;
+ top: -10px;
+}
+
+p {
+ margin-bottom: 20px;
+}
+
+#logo-orange {
+ color: orange;
+}
+
+.keyword {
+ font-weight: bold;
+ color: #799fcf;
+}
+
+.variable-name {
+ color: #ef2929;
+}
+
+.string {
+ color: #ad7fa8;
+ margin-left: 25px;
+}
+
+.post {
+ margin-bottom: 20px;
+}
+
+.doc {
+ color: #babdb6;
+ margin-left: 25px;
+}
+
+.doc a {
+ text-decoration: none;
+ color: #73d216;
+}
+
+.doc a:hover {
+ text-decoration: underline;
+}
+
+.doc p:last-child {
+ display: inline;
+}
+
+.content {
+ width: 750px;
+ margin: 10px auto;
+}
+
+
+/* .category { */
+/* display: block; */
+/* float: right; */
+/* padding: 0 5px; */
+/* border-left: 1px #202020 solid; */
+/* margin-left: 5px; */
+/* } */
+
+/* .category:hover { */
+/* border-left: 1px #ffffff solid; */
+/* background-color: #dddddd; */
+/* color: #404040; */
+/* text-decoration: none; */
+/* } */
+
+/* .clear { */
+/* clear: both; */
+/* } */
+
+/* .post { */
+/* margin-left: 20px; */
+/* } */
+
+/* .post, */
+/* .post header, */
+/* .post header h1, */
+/* .post .postcontent { */
+/* display: inline */
+/* } */
+
+/* .wordpress pre.src { */
+/* background-color: #002b36; */
+/* color: #839496; */
+/* font-family: "DejaVu Sans Mono", mono; */
+/* } */
+
+/* #logo { */
+/* float: left; */
+/* } */
+
+/* #sitetitle { */
+/* background-color: #000000; */
+/* color: #ffffff; */
+/* height: 70px; */
+/* line-height: 70px; */
+/* } */
+
+/* #sitetitle #blue { */
+/* color: #4169E1; */
+/* position: relative; */
+/* top: -5px; */
+/* } */
+
+/* #sitetitle #orange { */
+/* color: #ff9800; */
+/* position: relative; */
+/* top: 5px; */
+/* } */
+
+/* #sitesubtitle { */
+/* background-color: #404040; */
+/* color: #dddddd; */
+/* text-align: right; */
+/* height: 30px; */
+/* line-height: 30px; */
+/* border-top: 1px #808080 solid; */
+/* font-size: 16px; */
+/* } */
+
+/* #content { */
+/* width: 750px; */
+/* margin: 0 auto; */
+/* color: #ffffff; */
+/* margin-top: 2px; */
+/* } */
+
+/* #content h2 { */
+/* margin-bottom: 5px; */
+/* } */
+
+/* #feeds { */
+/* float: right; */
+/* background-color: #404040; */
+/* } */
+
+/* #feeds a { */
+/* color: #dddddd; */
+/* display: block; */
+/* padding: 5px; */
+/* text-decoration: none; */
+/* } */
+
+/* #feeds a:hover { */
+/* background-color: #dddddd; */
+/* color: #404040; */
+/* } */
+
+/* #pager { */
+/* background-color: #808080; */
+/* color: #000000; */
+/* padding: 0 5px; */
+/* position: relative; */
+/* } */
+
+/* #pager .nav-prev { */
+/* float: left; */
+/* } */
+
+/* #pager .nav-next { */
+/* float: right; */
+/* text-align: right; */
+/* } */
+
+/* #pager #current { */
+/* text-align: center; */
+/* } */
diff --git a/ryuslash/urls.py b/ryuslash/urls.py
new file mode 100644
index 0000000..917f2e9
--- /dev/null
+++ b/ryuslash/urls.py
@@ -0,0 +1,11 @@
+from django.conf.urls import patterns, url
+from django.contrib.staticfiles.urls import staticfiles_urlpatterns
+
+from aggregator.feeds import LatestPostsFeed
+
+urlpatterns = patterns('',
+ url(r'^((?P<cat>[a-z_-]+)/)?((?P<page>\d+)/)?$',
+ 'aggregator.views.posts'),
+ url(r'^feed/posts/$', LatestPostsFeed()))
+
+urlpatterns += staticfiles_urlpatterns()