From e69f7da0dc610528b19fa868f273ca4089b0f7fb Mon Sep 17 00:00:00 2001
From: luxagraf <sng@luxagraf.net>
Date: Sun, 8 Jun 2014 19:52:11 -0400
Subject: finished up notes app. still need to design and test, but it more or
 less works.

---
 .../templatetags/month_number_to_name.py           |  7 ++
 app/notes/admin.py                                 |  1 +
 app/notes/build.py                                 | 68 +++++++++++++++++++
 app/notes/models.py                                | 77 +++++++++++++++++-----
 app/notes/urls.py                                  |  8 +++
 app/notes/views.py                                 | 38 +++++++++++
 config/base_urls.py                                |  3 +-
 design/templates/archives/notes.html               | 44 +++++++++++++
 design/templates/archives/notes_date.html          | 73 ++++++++++++++++++++
 design/templates/details/note.html                 | 54 +++++++++++++++
 design/templates/details/note.txt                  |  8 +++
 11 files changed, 364 insertions(+), 17 deletions(-)
 create mode 100644 app/lib/templatetags/templatetags/month_number_to_name.py
 create mode 100644 app/notes/build.py
 create mode 100644 app/notes/urls.py
 create mode 100644 app/notes/views.py
 create mode 100644 design/templates/archives/notes.html
 create mode 100644 design/templates/archives/notes_date.html
 create mode 100644 design/templates/details/note.html
 create mode 100644 design/templates/details/note.txt

diff --git a/app/lib/templatetags/templatetags/month_number_to_name.py b/app/lib/templatetags/templatetags/month_number_to_name.py
new file mode 100644
index 0000000..69bd7e6
--- /dev/null
+++ b/app/lib/templatetags/templatetags/month_number_to_name.py
@@ -0,0 +1,7 @@
+import calendar
+from django import template
+register = template.Library()
+
+@register.filter
+def month_number_to_name(month_number):
+    return calendar.month_name[int(month_number)]
diff --git a/app/notes/admin.py b/app/notes/admin.py
index 03b8b37..17660c9 100644
--- a/app/notes/admin.py
+++ b/app/notes/admin.py
@@ -18,6 +18,7 @@ class NoteAdmin(OSMGeoAdmin):
     fieldsets = (
         ('Note', {
             'fields': (
+                'title',
                 'body_markdown',
                 ('twitter_send', 'slug'),
                 'point'
diff --git a/app/notes/build.py b/app/notes/build.py
new file mode 100644
index 0000000..44226f9
--- /dev/null
+++ b/app/notes/build.py
@@ -0,0 +1,68 @@
+from builder.base import *
+from .models import Note
+
+
+class BuildNotes(Build):
+    def build(self):
+        self.build_archive()
+        self.build_archive_year()
+        self.build_archive_month()
+        self.build_detail_pages()
+
+    def queryset(self):
+        return Note.objects.all()
+
+    def get_model(self):
+        return get_model('notes', 'note')
+
+    def build_detail_pages(self):
+        '''
+        Grab all the notes, render them to a template string and write that out to the filesystem
+        '''
+        for entry in self.queryset():
+            c = Context({'object': entry, 'MEDIA_URL': settings.BAKED_MEDIA_URL, 'IMAGES_URL': settings.BAKED_IMAGES_URL})
+            t = render_to_string('details/note.html', c).encode('utf-8')
+            path = 'notes/%s/' % (entry.date_created.strftime("%Y/%m").lower())
+            self.write_file(path, t, 'html', entry.slug)
+            s = render_to_string('details/note.txt', c).encode('utf-8')
+            self.write_file(path, s, 'txt', entry.slug)
+
+    def build_archive(self):
+        path = 'notes/'
+        c = Context({
+            'object_list': self.queryset(),
+            'MEDIA_URL': settings.BAKED_MEDIA_URL,
+            'IMAGES_URL': settings.BAKED_IMAGES_URL
+        })
+        t = render_to_string('archives/notes.html', c).encode('utf-8')
+        self.write_file(path, t)
+
+    def build_archive_year(self):
+        note = self.get_model()
+        years = note.objects.dates('date_created', 'year')
+        for year in years:
+            year = year.strftime('%Y')
+            qs = note.objects.filter(date_created__year=year).order_by('-date_created')
+            c = Context({
+                'year': year,
+                'object_list': qs
+            })
+            t = render_to_string('archives/notes_date.html', c).encode('utf-8')
+            fpath = 'notes/%s/' % (year)
+            self.write_file(fpath, t)
+
+    def build_archive_month(self):
+        note = self.get_model()
+        months = note.objects.dates('date_created', 'month')
+        for m in months:
+            year = m.strftime('%Y')
+            month = m.strftime('%m')
+            qs = note.objects.filter(date_created__year=year, date_created__month=month).order_by('-date_created')
+            c = Context({
+                'month': month,
+                'year': year,
+                'object_list': qs,
+            })
+            t = render_to_string('archives/notes_date.html', c).encode('utf-8')
+            fpath = 'notes/%s/%s/' % (year, month)
+            self.write_file(fpath, t)
diff --git a/app/notes/models.py b/app/notes/models.py
index 35680af..0a9e5c6 100644
--- a/app/notes/models.py
+++ b/app/notes/models.py
@@ -1,6 +1,16 @@
+'''
+TODO: 
+
+2) test urlize with markdown links
+3) parse out markdown wrapped links for twitter
+4) CSS
+6) Write JavaScript to automatically place map on current location
+'''
+
 import datetime
 from django.contrib.gis.db import models
 from django.template.defaultfilters import slugify
+from django.utils.html import urlize
 from django import forms
 from django.db.models.signals import post_save
 from django.dispatch import receiver
@@ -11,20 +21,24 @@ from twython import Twython
 # http://freewisdom.org/projects/python-markdown/
 import markdown
 
+
 def twitter_truncate(txt):
-    try:
-        return txt.split("|")[0]    
-    except:
-        return txt
+    return txt.split("|")[0]
+
 
 class Note(models.Model):
+    title = models.CharField(max_length=250, null=True, blank=True)
     slug = models.SlugField(unique_for_date='date_created', blank=True)
     date_created = models.DateTimeField('Date', blank=True)
     date_last_updated = models.DateTimeField('Date', blank=True)
     point = models.PointField()
     location = models.ForeignKey(Location, null=True, blank=True)
+    city_name = models.CharField(max_length=250, null=True, blank=True)
+    state_name = models.CharField(max_length=250, null=True, blank=True)
+    country_name = models.CharField(max_length=150, null=True, blank=True)
     body_html = models.TextField(blank=True)
     body_markdown = models.CharField('Note', max_length=450)
+    twitter_text = models.CharField('Twitter text', max_length=450, null=True, blank=True)
     twitter_id = models.CharField('twitter_id', max_length=450)
     twitter_send = models.BooleanField("send to twitter?", default=False)
     twitter_sent = models.BooleanField(default=False, blank=True)
@@ -33,7 +47,7 @@ class Note(models.Model):
         return self.slug
 
     def get_absolute_url(self):
-        return '/notes/%s/%s' % (self.date_created.strftime("%Y/%b").lower(), self.slug)
+        return '/notes/%s/%s' % (self.date_created.strftime("%Y/%m").lower(), self.slug)
 
     @property
     def state(self):
@@ -50,38 +64,69 @@ class Note(models.Model):
     @property
     def longitude(self):
         '''Get the site's longitude.'''
-        return self.point.x
+        return round(self.point.x, 2)
 
     @property
     def latitude(self):
         '''Get the site's latitude.'''
-        return self.point.y
+        return round(self.point.y, 2)
+
+    @property
+    def get_previous_published(self):
+        return self.get_previous_by_date_created()
+
+    @property
+    def get_next_published(self):
+        return self.get_next_by_date_created()
+
+    def link_twitter_names(self):
+        opts = {'username_include_symbol': True}
+        from twitter_text.autolink import Autolink
+        return Autolink(self.body_html).auto_link_usernames_or_lists(opts)
 
     def save(self):
-        self.body_html = markdown.markdown(self.body_markdown, extensions=['extra'], safe_mode=False)
+        self.body_html = markdown.markdown(urlize(self.body_markdown, 45), extensions=['extra'], safe_mode=False)
         self.date_last_updated = datetime.datetime.now()
         if not self.date_created:
             self.date_created = datetime.datetime.now()
         if not self.slug:
             self.slug = slugify(self.body_markdown)[:20]
-        try:
-            self.location = Location.objects.filter(geometry__contains=self.point).get()
-        except Location.DoesNotExist:
-            raise forms.ValidationError("There is no location associated with that point, add it:  %sadmin/locations/location/add/" % (settings.BASE_URL))
+        if not self.twitter_text:
+            self.twitter_text = twitter_truncate(self.body_markdown)
         super(Note, self).save()
 
 
+import requests
+import json
 @receiver(post_save, sender=Note)
 def post_save_events(sender, instance, **kwargs):
+    #if kwargs["created"]:
+    try:
+        l = Location.objects.filter(geometry__contains=instance.point).get()
+        instance.location = l
+        instance.city_name = l.name
+        instance.state_name = l.state.name
+        instance.country_name = l.state.country.name
+    except Location.DoesNotExist:
+        r_str = 'http://nominatim.openstreetmap.org/reverse?format=json&lat=%s&lon=%s&zoom=18' % (instance.latitude, instance.longitude)
+        response = requests.get(r_str)
+        data = json.loads(response.text)
+        adr = data.get('address', {})
+        instance.city_name = adr.get('hamlet') or adr.get('village') or adr.get('town') or adr.get('city')
+        instance.state_name = adr.get('state')
+        instance.country_name = adr.get('country')
     if instance.twitter_send and not instance.twitter_sent:
         t = Twython(settings.TWITTER_API_KEY, settings.TWITTER_API_SECRET, settings.TWITTER_ACCESS_TOKEN, settings.TWITTER_ACCESS_SECRET)
         geo = t.reverse_geocode(lat=instance.latitude, lon=instance.longitude, accuracy=1500, granularity="city")
         geo_id = geo['result']['places'][0]['id']
-        status = t.update_status(status=instance.body_markdown, place_id=geo_id)
+        status = t.update_status(status=instance.twitter_text, place_id=geo_id)
         instance.twitter_id = status['id']
         instance.twitter_sent = True
-        instance.save()
+    post_save.disconnect(post_save_events, sender=Note)
+    instance.save()
+    post_save.connect(post_save_events, sender=Note)
+
 
 def write_note(sender, instance, **kwargs):
-    if created:
-        pass 
+    if kwargs["created"]:
+        pass
diff --git a/app/notes/urls.py b/app/notes/urls.py
new file mode 100644
index 0000000..9018553
--- /dev/null
+++ b/app/notes/urls.py
@@ -0,0 +1,8 @@
+from django.conf.urls import patterns, url
+
+urlpatterns = patterns('',
+    url(r'(?P<year>\d{4})/(?P<month>\d{2})/(?P<slug>[-\w]+)$', 'notes.views.entry_detail'),
+    url(r'(?P<year>\d{4})/(?P<month>\d{2})/$', 'notes.views.date_list', name="notes_by_month"),
+    url(r'(?P<year>\d{4})/$', 'notes.views.date_list', name="notes_by_year"),
+    url(r'^$', 'notes.views.entry_list', name="notes_archive"),
+)
diff --git a/app/notes/views.py b/app/notes/views.py
new file mode 100644
index 0000000..2542293
--- /dev/null
+++ b/app/notes/views.py
@@ -0,0 +1,38 @@
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import RequestContext
+from notes.models import Note
+
+
+def entry_detail(request, year, month, slug):
+    context = {
+        'object': get_object_or_404(Note, slug__exact=slug),
+    }
+    return render_to_response(
+        'details/note.html',
+        context,
+        context_instance=RequestContext(request)
+    )
+
+
+def date_list(request, year, month=None):
+    if month:
+        qs = Note.objects.filter(date_created__year=year, date_created__month=month)
+    else:
+        qs = Note.objects.filter(date_created__year=year)
+    context = {
+        'year': year,
+        'month': month,
+        'object_list': qs,
+    }
+    return render_to_response(
+        "archives/notes_date.html",
+        context,
+        context_instance=RequestContext(request)
+    )
+
+
+def entry_list(request):
+    context = {
+        'object_list': Note.objects.all().order_by('-date_created').select_related(),
+    }
+    return render_to_response("archives/notes.html", context, context_instance=RequestContext(request))
diff --git a/config/base_urls.py b/config/base_urls.py
index 9cd4c5f..dd3ca2e 100644
--- a/config/base_urls.py
+++ b/config/base_urls.py
@@ -48,10 +48,11 @@ urlpatterns += patterns('',
     (r'^writing/', include('blog.urls')),
     (r'^projects/', include('projects.urls')),
     #Entry detail i.e. /year/month/day/my-title/
-	(r'(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'blog.views.entry_detail'),
+    (r'(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'blog.views.entry_detail'),
     # locations
     (r'^locations/', include('locations.urls')),
     (r'^photos/', include('photos.urls')),
+    (r'^notes/', include('notes.urls')),
     (r'^photo/', include('photos.detail_urls')),
     (r'^travel-guide/', include('guide.urls')),
     # map
diff --git a/design/templates/archives/notes.html b/design/templates/archives/notes.html
new file mode 100644
index 0000000..21f27b5
--- /dev/null
+++ b/design/templates/archives/notes.html
@@ -0,0 +1,44 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load html5_datetime %}
+{% block pagetitle %} Notes | luxagraf {% endblock %}
+{% block metadescription %} The LongHandPixels Blog Archive, covering HTML, CSS and other web nerdery.{% endblock %}
+{%block bodyid%}class="archive" id="blog-archive"{%endblock%}
+
+{% block primary %}
+    <ul class="bl" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
+        <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> &rarr; </li>
+        <li>Notes</li>
+    </ul>
+        <main role="main">
+        <h1>Notes</h1>
+{% for object in object_list %}
+        <article class="h-entry">
+            <div class="p-name e-content">
+            {{object.link_twitter_names|safe|amp|smartypants|urlizetrunc:45 }}
+            </div>
+            <footer>{% if object.location %}
+                <p class="h-adr meta location bl" itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo">
+                    <span class="p-locality">{{object.location.name|smartypants|safe}}</span>, 
+                    <span class="p-region">{{object.state_name}}</span>,
+                    <span class="p-country-name">{{object.location.state.country.name}}</span>
+                    <data class="p-latitude" value="{{object.latitude}}"></data>
+                    <data class="p-longitude" value="{{object.longitude}}"></data>
+                </p>{% endif %}
+                <p class="meta">
+                    <a class="u-url" href="{{object.get_absolute_url}}" rel="bookmark"><time datetime="{{object.date_created|html5_datetime}}">{{object.date_created|date:"d M Y"}}</time></a>
+                </p>{% if object.twitter_id %}
+                <p class="meta">
+                    <a rel="syndication" class="u-syndication" href="https://twitter.com/luxagraf/status/{{object.twitter_id}}">Twitter</a>
+                    <a href="https://twitter.com/intent/tweet?in_reply_to={{object.twitter_id}}">Reply</a>
+                    <a href="https://twitter.com/intent/retweet?tweet_id={{object.twitter_id}}">Retweet</a>
+                    <a href="https://twitter.com/intent/favorite?tweet_id={{object.twitter_id}}">Favourite</a>
+                </p>{% endif %}
+            </footer>
+        </article>
+{% endfor %}
+        </main>
+{% endblock %}
+
+
+
diff --git a/design/templates/archives/notes_date.html b/design/templates/archives/notes_date.html
new file mode 100644
index 0000000..9ac1c0e
--- /dev/null
+++ b/design/templates/archives/notes_date.html
@@ -0,0 +1,73 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load html5_datetime %}
+{% load month_number_to_name %}
+{% block pagetitle %} Notes Published in  {% if month %}{{month|month_number_to_name}}{%endif%} {{year}} | luxagraf{% endblock %}
+{% block bodyid %}class="archive" id="archive-{% if month %}{{month|month_number_to_name}}{%endif%}{{year}}"{%endblock%}
+{% block primary %}<ul class="bl crumbs" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb">
+        <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> &rarr; </li>
+        <li><a href="/notes/" itemprop="url"><span itemprop="title">Notes</span> &rarr;</li>
+        <li>{% if month %}<a href="/notes/{{year}}/" title="Notes published in {{year}}" itemprop="url">{%endif%}<span itemprop="title">{{year}}</span>{% if month %}</a> &rarr;{%endif%}</li>
+        {% if month %}<li itemprop="title">{{month|month_number_to_name}}</li>{%endif%}
+    </ul>
+    <main role="main">
+        <h1>Notes Published in {% if month %}{{month|month_number_to_name}}{%endif%} {{year}}</h1>{% if month %}{% for object in object_list %}
+        <article class="h-entry">
+            <div class="p-name e-content">
+            {{object.link_twitter_names|safe|urlizetrunc:45|amp|smartypants }}
+            </div>
+            <footer>{% if object.location %}
+                <p class="h-adr meta location bl" itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo">
+                    <span class="p-locality">{{object.location.name|smartypants|safe}}</span>, 
+                    <span class="p-region">{{object.state_name}}</span>,
+                    <span class="p-country-name">{{object.location.state.country.name}}</span>
+                    <data class="p-latitude" value="{{object.latitude}}"></data>
+                    <data class="p-longitude" value="{{object.longitude}}"></data>
+                </p>{% endif %}
+                <p class="meta">
+                    <a class="u-url" href="{{object.get_absolute_url}}" rel="bookmark"><time datetime="{{object.date_created|html5_datetime}}">{{object.date_created|date:"d M Y"}}</time></a>
+                </p>{% if object.twitter_id %}
+                <p class="meta">
+                    <a rel="syndication" class="u-syndication" href="https://twitter.com/luxagraf/status/{{object.twitter_id}}">Twitter</a>
+                    <a href="https://twitter.com/intent/tweet?in_reply_to={{object.twitter_id}}">Reply</a>
+                    <a href="https://twitter.com/intent/retweet?tweet_id={{object.twitter_id}}">Retweet</a>
+                    <a href="https://twitter.com/intent/favorite?tweet_id={{object.twitter_id}}">Favourite</a>
+                    </p>{% endif %}
+            </footer>
+        </article>
+        {% endfor %}
+    {% else %}
+<ul class="entry-list">{% regroup object_list by date_created.month as entries_by_month %}{% for month in entries_by_month %}
+        <span class="entry-list-month">{{ month.list.0.date_created|date:"F Y" }}</span>
+        {% for object in month.list %}
+
+        <article class="h-entry">
+            <div class="p-name e-content">
+            {{object.link_twitter_names|safe|amp|smartypants|urlizetrunc:45 }}
+            </div>
+            <footer>{% if object.location %}
+                <p class="h-adr meta location bl" itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo">
+                    <span class="p-locality">{{object.location.name|smartypants|safe}}</span>, 
+                    <span class="p-region">{{object.state_name}}</span>,
+                    <span class="p-country-name">{{object.location.state.country.name}}</span>
+                    <data class="p-latitude" value="{{object.latitude}}"></data>
+                    <data class="p-longitude" value="{{object.longitude}}"></data>
+                </p>{% endif %}
+                <p class="meta">
+                    <a class="u-url" href="{{object.get_absolute_url}}" rel="bookmark"><time datetime="{{object.date_created|html5_datetime}}">{{object.date_created|date:"d M Y"}}</time></a>
+                </p>{% if object.twitter_id %}
+                <p class="meta">
+                    <a rel="syndication" class="u-syndication" href="https://twitter.com/luxagraf/status/{{object.twitter_id}}">Twitter</a>
+                    <a href="https://twitter.com/intent/tweet?in_reply_to={{object.twitter_id}}">Reply</a>
+                    <a href="https://twitter.com/intent/retweet?tweet_id={{object.twitter_id}}">Retweet</a>
+                    <a href="https://twitter.com/intent/favorite?tweet_id={{object.twitter_id}}">Favourite</a>
+                    </p>{% endif %}
+            </footer>
+        </article>
+                 {% endfor %}
+        {% endfor %}
+    </ul>
+    {% endif %}
+                
+    </section>
+{% endblock%}
diff --git a/design/templates/details/note.html b/design/templates/details/note.html
new file mode 100644
index 0000000..fab554c
--- /dev/null
+++ b/design/templates/details/note.html
@@ -0,0 +1,54 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load html5_datetime %}
+{% load month_number_to_name %}
+{% block pagetitle %}{{object.title|title|smartypants|safe}} - Luxagraf, Notes{% endblock %}
+
+{% block metadescription %}{{object.body_html|striptags|safe}}{% endblock %}
+{%block extrahead%}
+     <link rel="canonical" href="http://luxagraf.net{{object.get_absolute_url}}" />
+     <meta name="ICBM" content="{{object.latitude}}, {{object.longitude}}" />
+     <meta name="geo.position" content="{{object.latitude}}; {{object.longitude}}" />
+     <meta name="geo.placename" content="{% if object.location.country.name == "United States" %}{{object.location.name|smartypants|safe}}, {{object.state.name}}{%else%}{{object.location.name|smartypants|safe}}, {{object.country.name}}{%endif%}"> 
+     <meta name="geo.region" content="{{object.country.iso2}}{%if object.state.code != '' %}-{{object.state.code}}{%endif%}">
+{%endblock%}
+								
+				
+{% block primary %}		
+        <article class="h-entry">
+            <div class="p-name e-content">
+            {{object.link_twitter_names|safe|amp|smartypants|urlizetrunc:45 }}
+            </div>
+            <footer>{% if object.location %}
+                <p class="h-adr meta location bl" itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo">
+                    <span class="p-locality">{{object.location.name|smartypants|safe}}</span>, 
+                    <span class="p-region">{{object.state_name}}</span>,
+                    <span class="p-country-name">{{object.location.state.country.name}}</span>
+                    <data class="p-latitude" value="{{object.latitude}}"></data>
+                    <data class="p-longitude" value="{{object.longitude}}"></data>
+                    </p>{% endif %}
+                <p class="meta">
+                    <a class="u-url" href="{{object.get_absolute_url}}" rel="bookmark"><time datetime="{{object.date_created|html5_datetime}}">{{object.date_created|date:"d M Y"}}</time></a>
+                </p>{% if object.twitter_id %}
+                <p class="meta">
+                    <a rel="syndication" class="u-syndication" href="https://twitter.com/luxagraf/status/{{object.twitter_id}}">Twitter</a>
+                    <a href="https://twitter.com/intent/tweet?in_reply_to={{object.twitter_id}}">Reply</a>
+                    <a href="https://twitter.com/intent/retweet?tweet_id={{object.twitter_id}}">Retweet</a>
+                    <a href="https://twitter.com/intent/favorite?tweet_id={{object.twitter_id}}">Favourite</a>
+                    </p>{% endif %}
+            </footer>
+
+        {% with object.get_next_published as next %}
+        {% with object.get_previous_published as prev %}
+        <nav id="page-navigation">
+            <ul>{% if prev%}
+                <li id="next"><span class="bl">Previous:</span> 
+                    <a href="{{ prev.get_absolute_url }}" rel="prev" title=" {{prev.title}}">{{prev.title|safe}}</a>
+                </li>{%endif%}{% if next%}
+                <li id="prev"><span class="bl">Next:</span> 
+                    <a href="{{ next.get_absolute_url }}" rel="next" title=" {{next.title}}">{{next.title|safe}}</a>
+                </li>{%endif%}
+            </ul>
+        </nav>{%endwith%}{%endwith%}
+    </article>
+{% endblock %}
diff --git a/design/templates/details/note.txt b/design/templates/details/note.txt
new file mode 100644
index 0000000..547ce79
--- /dev/null
+++ b/design/templates/details/note.txt
@@ -0,0 +1,8 @@
+{{object.title|safe}}
+{% for letter in object.title %}={%endfor%}
+
+    by Scott Gilbertson
+    <{{SITE_URL}}{{object.get_absolute_url}}>
+    {{object.pub_date|date:"l, d F Y"}}
+
+{{object.body_markdown|safe}}
-- 
cgit v1.2.3-70-g09d2