Hudarsono Hu avatar Hudarsono Hu committed 0179e2e

Add RSS feature

Comments (0)

Files changed (68)

Binary file modified.

+What is MeBlog?
+============================================================
+
+MeBlog is a blogging system which aim to let people easly
+customize the theme, widget, and plugin. This is work in
+progress. But at the curent release, main features for blogging
+already provided.
+
+
+
+Requirement
+============================================================
+
+MeBlog designed to run in Google AppEngine. It uses Django v1.2.3
+framework and django-appengine-helper.
+Media upload already supported, AppEngine need billing in order to
+enable media upload, but we still can set the daily budget.
+
+
+
+How To Install
+=============================================================
+
+Assuming that appengine account already created, and application
+name already registered in appengine.Follow simple steps
+below to install :
+-> Install AppEngine SDK
+   Download at : http://code.google.com/appengine/downloads.html
+
+-> Edit meblog/app.yaml
+   Change application name from 'meblog' to your registered name
+   in AppEngine
+
+-> (Optional) To have comment system on the blog, MeBlog can
+   integrate with Disquss. http://disqus.com
+   - copy first part of javascript to meblog/templates/front/post.html
+   - copy second part (comment count) to meblog/templates/front/footer.html
+   - set discuss to true in meblog/settings.py
+
+-> (Optional) To have web analytics, use Google Analytics.
+    - Copy javascript from Google Analytics to meblog/templates/front/footer.html
+    - set analytics to true in meblog/settings.py
+
+-> UPLOAD!.  #appcfg.py upload meblog
+-> Done!
+
-application: meblog
-version: 1
+application: hudarsono      # change this to your app-name
+version: 3
 runtime: python
 api_version: 1
 
 handlers:
-- url: /static
-  static_dir: static
+- url: /resources
+  static_dir: resources
 
 - url: /.*
   script: main.py
+
+
+builtins:
+- datastore_admin: on
+- appstats: on
Add a comment to this file

appengine_django/db/__init__.pyc

Binary file modified.

Add a comment to this file

appengine_django/db/base.pyc

Binary file modified.

Add a comment to this file

appengine_django/db/creation.pyc

Binary file modified.

Add a comment to this file

appengine_django/serializer/__init__.pyc

Binary file modified.

Add a comment to this file

appengine_django/serializer/json.pyc

Binary file modified.

Add a comment to this file

appengine_django/serializer/python.pyc

Binary file modified.

Add a comment to this file

appengine_django/serializer/pyyaml.pyc

Binary file modified.

Add a comment to this file

appengine_django/sessions/backends/__init__.pyc

Binary file modified.

Binary file modified.

context/context_processors.py

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 
 # this is a context processor for template
+import urllib
 from pages.models import Page
 from google.appengine.api import memcache
+from django.conf import settings
 
 def pages(request):
     if memcache.get('context_pages'):
                 context_pages.append({'name':page.name,
                                       'url':page.get_absolute_url()})
             memcache.set('context_pages', context_pages)
+            
+    if settings.BLOG_TITLE != '':
+        blog_title = settings.BLOG_TITLE
 
-    return {'context_pages':context_pages}
+    if settings.DISQUSS == 'True':
+        discuss=True
+    else:
+        discuss=False
+
+    if settings.ANALYTICS == 'True':
+        ga=True
+    else:
+        ga=False
+
+    return {'context_pages':context_pages, 'blog_title':blog_title, 'discuss':discuss, 'ga':ga}
+    
+def daily_quote(request):
+    if memcache.get('today_quote'):
+        todayquote = memcache.get('today_quote')
+    else:
+        f = urllib.urlopen('http://www.iheartquotes.com/api/v1/random?max_lines=1')
+        quotelines = f.readlines()
+        #remove last line
+        trimmedlines = quotelines[:-1]
+        todayquote = ''.join(trimmedlines)
+        memcache.set('today_quote', todayquote, 86400)
+        
+    return {'todayquote':todayquote}
Add a comment to this file

context/context_processors.pyc

Binary file modified.

Binary file modified.

Add a comment to this file

markdown/blockparser.pyc

Binary file modified.

Add a comment to this file

markdown/blockprocessors.pyc

Binary file modified.

Add a comment to this file

markdown/etree_loader.pyc

Binary file modified.

Add a comment to this file

markdown/extensions/__init__.pyc

Binary file modified.

Add a comment to this file

markdown/extensions/codehilite.pyc

Binary file modified.

Binary file modified.

Add a comment to this file

markdown/inlinepatterns.pyc

Binary file modified.

Binary file modified.

Add a comment to this file

markdown/postprocessors.pyc

Binary file modified.

Add a comment to this file

markdown/preprocessors.pyc

Binary file modified.

Add a comment to this file

markdown/treeprocessors.pyc

Binary file modified.

Binary file added.

media/fileform.py

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 #    You should have received a copy of the GNU General Public License
 #    along with MeBlog.  If not, see <http://www.gnu.org/licenses/>.
 
+
+import urllib
+import logging
+
 from appengine_django.models import BaseModel
 from google.appengine.ext import db
 from google.appengine.ext import blobstore
 
+from django.conf import settings
+
 # Create your models here.
 class Media(db.Model):
-	title = db.StringProperty()
-	created = db.DateTimeProperty(auto_now_add=True)
-	media = blobstore.BlobReferenceProperty()
-	filename = db.StringProperty()
-	filesize = db.IntegerProperty()
-	type = db.StringProperty()
+    title = db.StringProperty()
+    created = db.DateTimeProperty(auto_now_add=True)
+    media = blobstore.BlobReferenceProperty()
+    filename = db.StringProperty()
+    filesize = db.IntegerProperty()
+    type = db.StringProperty()
 
 
-	def get_absolute_url(self):
-		return '/media/item/%s' % self.media.key()
+    def get_absolute_url(self):
+        #domain = Site.objects.get_current()
+        return settings.SITE_URL+'/media/serve/%s' % self.key()
 
-	def get_delete_url(self):
-		return '/media/delete/%s' % self.media.key()
+    def get_download_url(self):
+        return '/media/download/%s' % self.key()
+        
+    def get_delete_url(self):
+        return '/media/delete/%s' % self.key()
-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 from media import models
 from fileform import FileForm
-from utilities.blob_helper import *
+from utilities import blob_helper
 from utilities.auth_helper import login_required
 
 
         form = FileForm(request.POST)
         if form.is_valid() and len(blob_info) == 1:
             media_item = models.Media(title=form.cleaned_data['title'],
-                                   media=blob_info[0].key(),
+                                   media=blob_info[0],
                                    filename = blob_info[0].filename,
                                    filesize = blob_info[0].size,
                                    type = blob_info[0].content_type)
             media_item.put()
             memcache.flush_all()
-            return HttpResponseRedirect('/posts/')
+            return HttpResponseRedirect('/media/')
 
         if len(media_blobs) == 0:
             request.session['upload_error'] = "Media file is required"
 													'upload_error': request.session.pop('upload_error', None),
 													'form': form})
 
+def serve(request, key):
+    media = models.Media.get(key)
+    return blob_helper.send_blob(request, media.media, save_as=False) 
+                                                    
 def download(request, key):
-    blob_key = str(urllib.unquote(key))
-    blob = blobstore.BlobInfo.get(blob_key)
-    return blob_helper.send_blob(request, blob, save_as=True)
+    media = models.Media.get(key)
+    return blob_helper.send_blob(request, media.media, save_as=True)

Binary file modified.

pages/contactform.py

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #

Binary file modified.

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
         return "/%s" % self.name
 
     def get_delete_url(self):
-        return "/page/delete/%s" % (self.name)
+        return "/page/delete/%s" % (self.key())
 
     def get_edit_url(self):
-        return "/page/edit/%s" % (self.name)
+        return "/page/edit/%s" % (self.key())
 
     def put(self):
-        self.check_double_name()
         self.populate_html()
         key = super(Page, self).put()
         return key
 
-    def check_double_name(self):
-        query = Page.all(keys_only=True)
-        query.filter('name = ', self.name)
-
-        page = query.get()
-
-        if page and (not self.is_saved() or self.key() != page):
-            raise PageConstraintViolation(self.name)
 
     def populate_html(self):
         md = markdown.Markdown(extensions=['codehilite'])
         if self.body:
             self.body_html = md.convert(self.body)
 
-class PageConstraintViolation(Exception):
-    def __init__(self, name):
-        super(PageConstraintViolation, self).__init__("Page with name '%s' was already used before" % name )

Binary file modified.

pages/pageform.py

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 
 class PageForm(forms.Form):
+    key = forms.CharField(required=False,widget=forms.HiddenInput())
     name = forms.CharField(max_length=100,widget=forms.TextInput(attrs={'class':'textInput'}))
     description = forms.CharField(max_length=300, required=False,widget=forms.TextInput(attrs={'class':'textInput'}))
     body = forms.CharField(widget=forms.Textarea)
         page.template = data['template']
         page.publish = data['publish']
         if commit: page.put()
-        return page
+        return page
+     
+    
+    # prevent the same page 's name
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        query = models.Page.all(keys_only=True)
+        query.filter('name = ', name)
+        
+        page = query.get()
+        
+        if page and (not self.cleaned_data['key']):
+            raise forms.ValidationError('Page name "%s" was already used before' % name)
+           
+        return name
+

Binary file modified.

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 
 @login_required
-def editPage(request, key_name):
+def editPage(request, key):
     pageForm = None
     if request.method == 'POST':
         form = PageForm(request.POST)
-        page = page = models.Page.get_by_key_name(key_name.replace('-',' '))
+        page = page = models.Page.get(key)
         if form.is_valid():
             form.save(page)
             memcache.flush_all()
             pageForm = PageForm(request.POST)
 
     if pageForm is None:
-        page = models.Page.get_by_key_name(key_name.replace('-',' '))
+        page = models.Page.get(key)
         if page:
-            pageForm = PageForm(initial={'name':page.name,
+            pageForm = PageForm(initial={'key':page.key(),
+                                         'name':page.name,
                                          'description':page.description,
                                          'body':page.body,
                                          'template':page.template,
                                                      'action':page.get_edit_url()})
 
 @login_required
-def delPage(request, key_name):
-    page = models.Page.get_by_key_name(key_name.replace('-',' '))
+def delPage(request, key):
+    page = models.Page.get(key)
     if page:
         page.delete()
         memcache.flush_all()
         if newMessage.is_valid():
             data = newMessage.cleaned_data
             #send message
-            mail.send_mail(sender="hudarsono.appspot.com <contact@hudarsono.appspot.com>",
-                              to="Hudarsono <hudarsono@gmail.com>",
+            mail.send_mail(sender='AppSpot <'+settings.AUTHOR_EMAIL+'>',
+                              to=settings.AUTHOR+' <'+settings.AUTHOR_EMAIL+'>',
                               subject="New Message from "+data['name'],
-                              body="Sender Email : "+data['email']+"\n Message : "+data['message'])
+                              body="Sender Email : "+data['email']+"\n\nMessage :\n"+data['message'])
 
             msg = 'Thanks for your message, will get back to you soon.'
+
         else:
             form = ContactForm(request.POST)
 

Binary file modified.

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 from appengine_django.models import BaseModel
 from google.appengine.ext import db
+from google.appengine.api import users
 
 # Create your models here.
 import datetime
         return "/post/edit/%04d/%02d/%02d/%s" % (self.pub_date.year,
                                                    self.pub_date.month,
                                                    self.pub_date.day,
-                                                   self.title.replace(' ','-'))
+                                                   self.key())
 
     def get_delete_url(self):
         return "/post/delete/%04d/%02d/%02d/%s" % (self.pub_date.year,
                                                    self.pub_date.month,
                                                    self.pub_date.day,
-                                                   self.title.replace(' ','-'))
+                                                   self.key())
 
     def trunc_body(self):
         if len(self.body) > 500:
 
 
     def put(self):
-        self.check_double_title()
         self.populate_html()
+        
+        # get author
+        self.author = users.get_current_user()
         key = super(Post, self).put()
         return key
 
-    def check_double_title(self):
-        query = Post.all(keys_only=True)
-        query.filter('title = ', self.title)
-
-        post = query.get()
-
-        if post and (not self.is_saved() or self.key() != post):
-            raise TitleConstraintViolation(self.title)
 
     def populate_html(self):
         md = markdown.Markdown(extensions=['codehilite'])
         if self.body:
             self.body_html = md.convert(self.body)
 
-
-class TitleConstraintViolation(Exception):
-    def __init__(self, title):
-        super(TitleConstraintViolation, self).__init__("Title '%s' was already used before" % title )

posts/postform.py

-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
 
 
 class PostForm(forms.Form):
+    key = forms.CharField(required=False, widget=forms.HiddenInput())
     title = forms.CharField(max_length=100,widget=forms.TextInput(attrs={'class':'textInput'}))
     body = forms.CharField(widget=forms.Textarea())
     category = forms.CharField(max_length=30,widget=forms.TextInput(attrs={'class':'textInput'}))
         post.tags = data['tags'].split()
         if commit: post.put()
         return post
+        
+    
+    def clean_title(self):
+        title = self.cleaned_data['title']
+        query = models.Post.all(keys_only=True)
+        query.filter('title = ', title)
+
+        post = query.get()
+
+        if post and not self.cleaned_data['key']:
+            raise forms.ValidationError('Title "%s" already used before.' % title)
+
+        return title
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
+#
+#    This file is part of MeBlog.
+#
+#    MeBlog is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    MeBlog is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with MeBlog.  If not, see <http://www.gnu.org/licenses/>.
+
 from django.contrib.syndication.views import Feed
 from posts.models import Post
 from django.conf import settings
-#    Copyright 2010 Hudarsono <http://hudarsono.me>
+#    Copyright 2010 Hudarsono <http://blog.hudarsono.me>
 #
 #    This file is part of MeBlog.
 #
       cat_list[p.category] = 1
 
   sorted_cat_list = []
-  for cat in sorted(cat_list):
-    sorted_cat_list.append({'category': cat,
-                  'count':cat_list[cat],
-                  'url': '/posts/category/%s' % cat.replace(' ','-'),
-                  })
+  if cat_list:
+      for cat in sorted(cat_list):
+        sorted_cat_list.append({'category': cat,
+                      'count':cat_list[cat],
+                      'url': '/posts/category/%s' % cat.replace(' ','-'),
+                      })
+
 
   # get all tags
   tag_list = {}
         tag_list[tag] = 1
 
   sorted_tag_list = []
-  for tag in sorted(tag_list.iterkeys()):
-    sorted_tag_list.append({'tag': tag,
-                                'count': tag_list[tag],
-                                'url': '/posts/tag/%s' % (tag),
-                               })
+
+  if tag_list:
+      for tag in sorted(tag_list.iterkeys()):
+        sorted_tag_list.append({'tag': tag,
+                                    'count': tag_list[tag],
+                                    'url': '/posts/tag/%s' % (tag),
+                                   })
 
   cat_tag  = {'tag_list': sorted_tag_list,
           'cat_list': sorted_cat_list}
 
 
 @login_required
-def editPost(request, year, month, day, key_name):
+def editPost(request, year, month, day, key):
   if request.method == 'POST':
-    post = models.Post.get_by_key_name(key_name)
+    post = models.Post.get(key)
     if post:
       form = postform.PostForm(request.POST)
       if form.is_valid():
     return HttpResponseRedirect('/posts/')
 
   if request.method == 'GET':
-    post = models.Post.get_by_key_name(key_name)
-    import logging
-    logging.info(post.title)
-    logging.info(post.body)
-    editPostForm = postform.PostForm(initial={
+    post = models.Post.get(key)
+    editPostForm = postform.PostForm(initial={'key':post.key(),
                           'title': post.title,
                           'body': post.body,
                           'category': post.category,
 
 
 @login_required
-def delPost(request, year, month, day, key_name):
-  post = models.Post.get_by_key_name(key_name)
+def delPost(request, year, month, day, key):
+  post = models.Post.get(key)
   if post:
     post.delete()
 

Binary file modified.

Binary file modified.

resources/css/admin.css

 	color:red;
 	list-style:none;
 	display:inline;
+}
+
+.footer, .footer a{
+	margin-top:10px;
+	color:white;
+	text-shadow:none;
 }

resources/css/theme.css

 	text-shadow: 0px 1px 1px #fff;
 }
 
+header hgroup, hgroup a{
+    color:white;
+    text-shadow:none;
+    text-decoration:none;
+}
 
 #nav {
-	margin-top:100px;
+	margin-top:0px;
 }
 
 #nav ul {
 
 #side-menu .nav-cat{
 	padding: 3px;
-	margin-top:8px;
 }
 
 #side-menu .nav-cat ul{
 	list-style:none;
+	margin-bottom:10px;
 }
 
 #side-menu .nav-cat li{
 	display:inline;
 	margin-left:0;
 }
+
+.footer, .footer a{
+	margin-top:10px;
+	color:white;
+	text-shadow:none;
+}
+
+span.msg{
+	font-weight:bold;
+	font-size:12px;
+}
+
+
+/* Css Blockquote */
+blockquote p{
+  font: 1.2em/1.6em Georgia, "Times New Roman", Times, serif;
+  width: 400px;
+  background: url(/resources/img/small/close_quote.gif) no-repeat right bottom;
+  padding-left: 18px;
+  text-indent: -18px;
+  text-align:center;
+}
+
+blockquote p:first-letter {
+  background: url(/resources/img/small/open_quote.gif) no-repeat left top;
+  padding-left: 18px;
+  font: italic 1.4em Georgia, "Times New Roman", Times, serif;
+}
+
Add a comment to this file

resources/img/small/close_quote.gif

Added
New image
Add a comment to this file

resources/img/small/doublequote.gif

Added
New image
Add a comment to this file

resources/img/small/download.png

Added
New image
Add a comment to this file

resources/img/small/open_quote.gif

Added
New image
Add a comment to this file

resources/img/small/rssfeed.jpg

Added
New image
 
 import os
 
-DEBUG = True
+DEBUG = False
 TEMPLATE_DEBUG = DEBUG
 
 ROOT_PATH = os.path.dirname(__file__)
 MIDDLEWARE_CLASSES = (
     'django.middleware.common.CommonMiddleware',
     'django.contrib.sessions.middleware.SessionMiddleware',
+    'google.appengine.ext.appstats.recording.AppStatsDjangoMiddleware',
 #    'django.contrib.auth.middleware.AuthenticationMiddleware',
 #    'django.middleware.doc.XViewMiddleware',
 )
 
     # context processor to get all pages
     'context.context_processors.pages',
+    
+    # get daily quote 
+    'context.context_processors.daily_quote',
 
 #    'django.core.context_processors.media',  # 0.97 only.
 #    'django.core.context_processors.request',
      'markdown',
      'pygments',
      'utilities',
-#    'django.contrib.auth',
-#    'django.contrib.contenttypes',
-#    'django.contrib.sessions',
-#    'django.contrib.sites',
 )
 
-
 # APP SETTINGS
+APPNAME = 'hudarsono'
 BLOG_TITLE = 'Hudarsono\'s Blog'
-SITE_URL = 'localhost'
+SITE_URL = 'http://hudarsono.appspot.com'
 AUTHOR = 'Hudarsono'
 AUTHOR_EMAIL = 'hudarsono@gmail.com'
 PAGESIZE = 10
+
+# Extension
+DISQUSS = 'True'      #Disquss is a comment system for blog.  http://disqus.com
+ANALYTICS = 'True'
+

templates/admin/base.html

 		{% block content %}{% endblock %}
 		</div>
 	</div>
+	
+	{% include 'admin/footer.html' %}
 </div>
 </body>
 </html>

templates/admin/footer.html

+<div class="grid_12 footer">
+	(c)2010 Powered by
+	<a href="http://bitbucket.org/hudarsono/meblog">MeBlog</a>
+</div>

templates/admin/medialist.html

 				<th class="first menu">Action</th>
 				<th>Title</th>
 				<th>Filename</th>
-				<th>Type</th>
-				<th>Size</th>
+				<th>Url</th>
 				<th class="last date">Created</th>
 			</tr>
 		</thead>
 		{% if list.count > 0 %}
 			{% for l in list %}
 				<tr>
-					<td><a href="{{ l.get_delete_url }}"><img src="/resources/img/small/trash.png" border="0" title="Delete"></a></td>
+					<td><a href="{{ l.get_delete_url }}"><img src="/resources/img/small/trash.png" border="0" title="Delete"></a> | 
+                        <a href="{{ l.get_download_url }}"><img src="/resources/img/small/download.png" border="0" title="Download"></a></td>
 					<td>{{ l.title }}</td>
 					<td>{{ l.filename }}</td>
-					<td>{{ l.type }}</td>
-					<td>{{ l.filesize }}</td>
+					<td>{{ l.get_absolute_url }}</td>
 					<td>{{ l.created.year }}-{{l.created.month }}-{{ l.created.day }}</td>
 				</tr>
 			{% endfor %}

templates/admin/newpage.html

 
 {% block content %}
 <form class="uniform" method="POST" action="{% if action %}{{ action }}{% else %}/page/new/{% endif %}">
+{% if pageForm.key %}{{ pageForm.key }}{% endif %}
 <fieldset>
 <div class="left-form">
 			<div class="ctrlHolder">

templates/admin/newpost.html

 
 {% block content %}
 <form class="uniform" method="POST" action="{% if action %}{{ action }}{% else %}/post/new/{% endif %}">
+{% if postForm.key %}{{ postForm.key }}{% endif %}
 <fieldset>
 <div class="left-form">
 			<div class="ctrlHolder">

templates/admin/upload.html

 {% extends 'admin/base.html' %}
 
 {% block content %}
+<div style="width:420px">
 	<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
 	{% if upload_error %}<span>{{ upload_error }}</span>{% endif %}
 
 	<input class="submit cancel" type="button" value="Cancel" onclick="history.go(-1)"/>
 	</p>
 	</form>
+</div>
 {% endblock %}

templates/front/base.html

 	</div>
 
 	<div class="clear"></div>
+
+	{% include 'front/footer.html' %}
 </div>
+
 </body>
 </html>

templates/front/footer.html

+<div class="grid_12 footer">
+	(c)2010 Powered by
+	<a href="http://bitbucket.org/hudarsono/meblog">MeBlog</a>
+</div>
 
+<!-- Disquss -->
+{% if discuss %}
+<script type="text/javascript">
+var disqus_shortname = 'hudarsonosblog';
+(function () {
+  var s = document.createElement('script'); s.async = true;
+  s.src = 'http://disqus.com/forums/hudarsonosblog/count.js';
+  (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
+}());
+</script>
+{% endif %}
+
+<!-- Google Analytics -->
+{% if ga %}
+<script type="text/javascript">
+
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-6599473-6']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+
+</script>
+{% endif %}

templates/front/header.html

-<div class="grid_6">
+<header>
+<div class="grid_12">
+	<hgroup>
+		{% if blog_title %}<a href="/"><h1>{{ blog_title }}</h1></a>{% endif %}
+		{% if todayquote %}<blockquote style="float:left"><p>{{ todayquote}}</p></blockquote>{% endif %}
+	</hgroup>
+</div>
+<div class="clear"></div>
+<div class="grid_3">
 	&nbsp;
 </div>
 
-<div class="grid_6">
+<div class="grid_9">
 	<div id="nav">
 		<ul>
 			<li><a href="/">Home</a></li>
 		</ul>
 	</div>
 </div>
+</header>

templates/front/post.html

 		{{ post.body_html|safe }}
 		{% endautoescape %}
 	</p>
-	<div class="clear"></div>
+	<div class="clear"  style="height:50"></div>
+
+	{% if discuss %}
+	<div id="disqus_thread"></div>
+	<script type="text/javascript">
+	  /**
+	    * var disqus_identifier; [Optional but recommended: Define a unique identifier (e.g. post id or slug) for this thread]
+	    */
+	  (function() {
+	   var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+	   dsq.src = 'http://hudarsonosblog.disqus.com/embed.js';
+	   (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+	  })();
+	</script>
+	<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript=hudarsonosblog">comments powered by Disqus.</a></noscript>
+	<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>
+	{% endif %}
 {% endblock %}
 
 

templates/front/stream.html

 {% if posts %}
 {% for p in posts %}
 	<h3 class="title"><a href="{{ p.get_absolute_url }}">{{ p.title}}</a></h3>
-	<span class="date">Writen at {{ p.pub_date.year }}-{{ p.pub_date.month }}-{{ p.pub_date.day }}</span>
+	<span class="date">Writen at {{ p.pub_date.year }}-{{ p.pub_date.month }}-{{ p.pub_date.day }} by {{ p.author.nickname }}</span>
 	<p>
 		{% autoescape off %}
 		{{ p.trunc_body }}
 
 {% block side_menu %}
 <div class="widget">
+<span class="side-title">Subscribe</span>
+<div class="nav-cat">
+	<ul>
+		<li><a href="/feeds/latest/"><img src="/resources/img/small/rssfeed.jpg"</a></li>
+	</ul>
+</div>
+</div>
+
+
+<div class="widget">
 <span class="side-title">Categories</span>
 <div class="nav-cat">
 	<ul>

templates/pages/base.html

 	{% if page.navbar %}
 		<div id="main-content" class="grid_9">
 			<div class="content">
-				{% block main_content %}{% endblock %}
+				{% block content %}{% endblock %}
 			</div>
 		</div>
 
 	{% else %}
 		<div id="main-content" class="grid_12">
 			<div class="content">
-				{% block main_content %}{% endblock %}
+				{% block content_wide %}{% endblock %}
 			</div>
 		</div>
 	{% endif %}

templates/pages/contact.html

 			</div>
 			<div class="ctrlHolder">
 				<label for="id_email" style="display:block">Email {{ form.email.errors }}</label>
-				<input id="id_email" class="textInput" type="text" size="50" name="name" />
+				<input id="id_email" class="textInput" type="text" size="50" name="email" />
 			</div>
 			<div class="ctrlHolder">
 				<label for="id_message" style="display:block">Message {{ form.message.errors }}</label>
-				<textarea id="id_message" name="body" cols="40" rows="18"></textarea>
+				<textarea id="id_message" name="message" cols="40" rows="18"></textarea>
 			</div>
-			{% if msg %}<span class="msg">{{ msg }}</span>{% endif %}
+			<div class="ctrlHolder">
+				{% if msg %}<span class="msg"><strong>{{ msg }}</strong></span>{% endif %}
+			</div>
 
 			<div class="buttonHolder"><input class="submit" type="submit" value="Send" /></div>
 		</fieldset>

templates/pages/default.html

 {% extends "pages/base.html" %}
 
-{% block main_content %}
-{% if page %}
-	{% autoescape off %}
-	{{ page.body_html }}
-	{% endautoescape %}
-{% else %}
-	<h3>Sorry, this page is not ready yet. Please come back soon.</h3>
-{% endif %}
-{% endblock %}
 
 {% if page.navbar %}
+	{% block content %}
+		{% if page %}
+			<h3>{{ page.name }}</h3>
+			{% autoescape off %}
+			{{ page.body_html }}
+			{% endautoescape %}
+		{% else %}
+			<h3>Sorry, this page is not ready yet. Please come back soon.</h3>
+		{% endif %}
+	{% endblock %}
+
 	{% block side_menu %}{% endblock %}
-{% endif %}
+
+{% else %}
+	{% block content_wide %}
+		{% if page %}
+			<h3>{{ page.name }}</h3>
+			{% autoescape off %}
+			{{ page.body_html }}
+			{% endautoescape %}
+		{% else %}
+			<h3>Sorry, this page is not ready yet. Please come back soon.</h3>
+		{% endif %}
+	{% endblock %}
+{% endif %}
 #     (r'^admin/', include('django.contrib.admin.urls')),
 
 	# serve static resources
-	(r'^resources/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),
+	#(r'^resources/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }),
 
 	(r'^$', 'posts.views.stream'),
 
     (r'^page/delete/([-\w]+)', 'pages.views.delPage'),
 
     (r'^media/$', 'media.views.listMedia'),
+    (r'^media/serve/([-\w]+)', 'media.views.serve'),
     (r'^media/delete/([-\w]+)', 'media.views.delMedia'),
 	(r'^media/upload/', 'media.views.upload'),
     (r'^media/download/([-\w]+)', 'media.views.download'),
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.