Index: applications/mobileblur/controllers/default.py
==================================================================
--- applications/mobileblur/controllers/default.py
+++ applications/mobileblur/controllers/default.py
@@ -21,11 +21,18 @@
     if login_form.accepts(request):
         try:
             results = newsblur.login(login_form.vars["username"], login_form.vars["password"])
             response.cookies["nb_cookie"] = newsblur.cookies["newsblur_sessionid"]
             response.cookies["nb_cookie"]["path"] = "/"
-            print "cookie =", newsblur.cookies
             redirect(URL("index"))
         except Exception as ex:
             login_form.insert(-1, ex.message)
+            login_form._class = "alert-message block-message error"
 
     return dict(login_form=login_form)
+
+
+def logout():
+    response.cookies["nb_cookie"] = ""
+    response.cookies["nb_cookie"]["expires"] = -10
+    response.cookies["nb_cookie"]["path"] = "/"
+    redirect(URL("index"))

Index: applications/mobileblur/controllers/feeds.py
==================================================================
--- applications/mobileblur/controllers/feeds.py
+++ applications/mobileblur/controllers/feeds.py
@@ -1,13 +1,32 @@
 # -*- coding: utf-8 -*-
 
 from pprint import pprint
+import time
 
 def view():
-    stories = newsblur.feed(request.args[0])["stories"]
-    feeds = newsblur.feeds(flat=True)["feeds"]
-    feed = [feed for feed in feeds.itervalues() if feed["id"]==int(request.args[0])][0]
+    print ""
+    s = time.time()
+    feed = newsblur.feed(request.args[0])
+    stories = feed["stories"]
+    print time.time() - s
+
+    print feed.keys()
+
+    if not feed.has_key("feed_title"):
+        s = time.time()
+        feeds = newsblur.feeds(flat=True)["feeds"]
+        print time.time() - s
+
+        s = time.time()
+        feed = [feed for feed in feeds.itervalues() if feed["id"]==int(request.args[0])][0]
+        print time.time() - s
+
+    response.title = feed["feed_title"]
+
     return dict(stories=stories, feed=feed)
+
 
 def mark_read():
-    newsblur.mark_feed_as_read(request.vars["feed"])
+    if len(request.args) > 0:
+        newsblur.mark_feed_as_read(request.args[0])
     redirect(URL("default", "index"))

Index: applications/mobileblur/controllers/stories.py
==================================================================
--- applications/mobileblur/controllers/stories.py
+++ applications/mobileblur/controllers/stories.py
@@ -3,6 +3,10 @@
 from pprint import pprint
 
 def view():
     stories = newsblur.feed(request.vars["feed_id"])["stories"]
     story = [story for story in stories if story["id"]==request.vars["story"]][0]
-    return dict(story=story)
+    return dict(story=story, feed_id=request.vars["feed_id"])
+
+def mark_read():
+    results = newsblur.mark_story_as_read(request.vars["story_id"], request.vars["feed_id"])
+    redirect(URL("default", "index"))

Index: applications/mobileblur/models/0_helpers.py
==================================================================
--- applications/mobileblur/models/0_helpers.py
+++ applications/mobileblur/models/0_helpers.py
@@ -2,11 +2,10 @@
 newsblur = newsblur.NewsBlur()
 
 threshold = 0
 thresholds = ["nt", "ps", "ng"]  # indices -1, 0, 1 for negative, neutral, and positive intelligence filters
 
-print request.cookies
 if [request.application, request.controller, request.function] != [request.application, "default", "login"]:
     if "nb_cookie" not in request.cookies.keys():
         redirect(URL("default", "login"))
     else:
         newsblur.cookies["newsblur_sessionid"] = request.cookies["nb_cookie"].value

Index: applications/mobileblur/modules/newsblur.py
==================================================================
--- applications/mobileblur/modules/newsblur.py
+++ applications/mobileblur/modules/newsblur.py
@@ -21,12 +21,10 @@
         Required parameters, username and password, must be of string type.
         '''
 
         url = nb_url + 'api/login'
         results = requests.post(url, data={"username": username, "password": password})
-        print "results.cookies =", results.cookies
-        print type(results.cookies)
         self.cookies = results.cookies
         results = simplejson.loads(results.content)
         if results["authenticated"] is False:
             raise Exception("The newsblur credentials you provided are invalid")
         return results

Index: applications/mobileblur/static/css/base.css
==================================================================
--- applications/mobileblur/static/css/base.css
+++ applications/mobileblur/static/css/base.css
@@ -25,17 +25,17 @@
 - form and table padding
 - code blocks
 - left and right padding to quoted text
 - page layout alignment, width and padding (change this for spaces)
 - column widths (change this to use left_sidebar and right_sidebar)
-- backrgound images and colors (change this for colors)
+- background images and colors (change this for colors)
 - web2py specific (.flash, .error)
 
 Notice:
 - even if you use a different layout/css you may need classes .flash and .error
 - this is all color neutral except for #349C01 (header, links, lines)
-- there are two backrgound images: images/background.png and images/header.png
+- there are two background images: images/background.png and images/header.png
 
 License: This file is released under BSD and MIT
 
 */
 
@@ -143,13 +143,14 @@
 /* always force a scrollbar in non-IE */ 
 html { overflow-y: scroll; }
  
 /* Accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test */
 a:hover, a:active { outline: none; }
-
+/*
 a, a:active, a:visited { color:#607890; }
 a:hover { color:#036; }
+*/
 
 ul, ol { margin-left: 1.8em; }
 ol { list-style-type: decimal; }
 
 /* Remove margins for navigation lists */
@@ -327,63 +328,18 @@
 fieldset { border: 1px solid #dedede; padding: 6px; }
 legend { font-weight: bold; }
 
 input:focus, textarea:focus { background: #fafafa; }
 
-p {text-indent:30px;}
-
-p, blockquote {    
-    margin-bottom: 10px;
-}
-
 h1,h2,h3,h4,h5,h6 { line-height: 170%; }
 h1 {font-size: 2.0em;}
 h2 {font-size: 1.8em;}
 h3 {font-size: 1.4em;}
 h4 {font-size: 1.2em;}
 h5 {font-size: 1.0em;}
 h6 {font-size: 0.8em;}
 
-/*********** page layout alignment, width and padding ***********/
-/*body {background-color: #000;}*/
-#container, #header, #page, #content, #statusbar,
-#footer, #wrapper { display:block; line-height: 170%; }
-#wrapper {width: 900px;}
-#container {
-    margin: 0 auto;
-    padding: 0;
-}
-#wrapper {margin: 0 auto;} 
-#wrapper {background-color: #fff; padding: 5px;} 
-#statusbar { margin: 5px 0px 20px 0px;}
-#footer {    
-    margin-top: 30px;    
-    padding: 5px;    
-}
-#statusbar, #footer {    
-    background: #eaeaea; 
-    border-top: 1px #aaa solid;    
-}
-#logo {
-    width: 68px;
-    height: 62px;
-    background: url(../images/logo.png);
-}
-#appname {
-    color: #cccccc;
-}
-
-#right_sidebar { width: 160px; float:right; display: none; }
-#left_sidebar { width: 160px; float:left; display: none; }
-#content { float: left; /*width: 740px;*//*width: 63%;*/ /*width: 640px; float:left;*/ } /* uncomment this if you are going to use sidebars */
- 
-.auth_navbar {
-   top: 0px;
-   float: right;
-   padding: 3px 10px 3px 10px; 
-}
-
 /*********** web2py specific ***********/
 div.flash {
     font-weight: bold;
     display: none;
     position: fixed;    
@@ -533,10 +489,15 @@
   /* Uncomment if you don't want iOS and WinMobile to mobile-optimize the text for you
      j.mp/textsizeadjust 
   html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
 }
 
+@media handheld {
+    body {
+    }
+}
+
 
 /* 
  * print styles
  * inlined to avoid required HTTP connection www.phpied.com/delay-loading-your-print-css/ 
  */
@@ -552,5 +513,82 @@
   @page { margin: 0.5cm; }
   p, h2, h3 { orphans: 3; widows: 3; }
   h2, h3{ page-break-after: avoid; }
 }
 
+body {
+/*    background-color: #f2c84b;*/
+    color: #493F3E
+}
+
+header {
+    background-color: #95392E;
+    padding: 1%;
+    border-bottom: 1px solid #95392E;
+    color: white;
+}
+header > h1 > a {
+    text-decoration: none;
+    color: white;
+    font-weight: bold;
+}
+
+#story > header > a {
+    color: white;
+}
+
+header > a> h2 {
+/*    border-top: 1px solid white;*/
+    color: white;
+}
+
+#story-list {
+/*    background-color: #f2c84b;*/
+}
+
+#story-list > .story > a, .feed > a {
+    text-decoration: none;
+    font-weight: bold;
+    margin-top: 0;
+}
+#story-list > .story > p {
+    font-size: .75em;
+}
+
+#story-list > .story > .read {
+    color: #D99B48;
+}
+#story-list > .story > .unread, .feed > a {
+    color: #C57E3C;
+}
+
+#story-list > .story, .feed {
+    padding: .5%;
+    border-top: 1px solid #95392E;
+    margin-top: .33%;
+}
+
+span.ps, span.nt, span.ng {
+    padding: .05em;
+    border-radius: 5px;
+}
+span.ps {
+    background-color: #ABAA7A;
+}
+span.nt {
+    background-color: #D99B48;
+}
+span.ng {
+    background-color: red;
+}
+
+footer {
+    background-color: #95392E;
+    padding: 1%;
+    border-top: 1px solid #95392E;
+    color: white;
+}
+footer > a {
+    text-decoration: none;
+    color: white;
+    font-weight: bold;
+}

Index: applications/mobileblur/views/default/index.html
==================================================================
--- applications/mobileblur/views/default/index.html
+++ applications/mobileblur/views/default/index.html
@@ -1,12 +1,10 @@
-{{left_sidebar_enabled=right_sidebar_enabled=False}}
 {{extend 'layout.html'}}
 
 {{ for feed in feeds.itervalues(): }}
-    {{ if threshold == -1 and feed["ng"] > 0: }} <span class='ng'>[ {{= feed["ng"] }} ]</span> {{ pass }}
-    {{ if threshold <= 0 and feed["nt"] > 0: }} <span class='nt'>[ {{= feed["nt"] }} ]</span> {{ pass }}
-    {{if feed["ps"] > 0: }}<span class='ps'>[ {{= feed["ps"] }} ]</span> {{ pass }}
-    <a href="{{= URL(c="feeds", f="view", args=[feed["id"]]) }}">{{= feed["feed_title"] }}</a><br />
+    <div class="feed">
+        {{ if threshold == -1 and feed["ng"] > 0: }} <span class='ng'>{{= feed["ng"] }}</span> {{ pass }}
+        {{ if threshold <= 0 and feed["nt"] > 0: }} <span class='nt'>{{= feed["nt"] }}</span> {{ pass }}
+        {{if feed["ps"] > 0: }}<span class='ps'>{{= feed["ps"] }}</span> {{ pass }}
+        <a href="{{= URL(c="feeds", f="view", args=[feed["id"]]) }}">{{= feed["feed_title"] }}</a><br />
+    </div>
 {{ pass }}
-
-{{block left_sidebar}}New Left Sidebar Content{{end}}
-{{block right_sidebar}}New Right Sidebar Content{{end}}

Index: applications/mobileblur/views/feeds/view.html
==================================================================
--- applications/mobileblur/views/feeds/view.html
+++ applications/mobileblur/views/feeds/view.html
@@ -1,12 +1,28 @@
-{{left_sidebar_enabled=right_sidebar_enabled=False}}
 {{extend 'layout.html'}}
 
-<h1>{{= feed["feed_title"] }}</h1>
-<a href="{{= URL("mark_read", vars=dict(feed=feed["id"])) }}"> Mark feed as read</a>
-
-{{ for story in stories: }}
-    <a href="{{= URL(c="stories", f="view", vars=dict(story=story["id"], feed_id=feed["id"])) }}"><h2>{{= story["story_title"] }}</h2></a>
-{{ pass }}
-
-{{block left_sidebar}}New Left Sidebar Content{{end}}
-{{block right_sidebar}}New Right Sidebar Content{{end}}
+{{ block header_bonus }}
+    <h2>{{= feed["feed_title"] }}</h2>
+    <a href="{{= URL("mark_read", args=[feed["id"]]) }}" class="button">Mark feed as read</a>
+{{ end }}
+
+<section id="story-list">
+{{
+import time 
+s = time.time()
+}}
+    {{ 
+        for story in stories: 
+        if sum([v for k,v in story["intelligence"].iteritems()]) < threshold:
+            continue
+    }}
+
+        {{ print story["read_status"] }}
+        <div class="story">
+            <a href="{{= URL(c="stories", f="view", vars=dict(story=story["id"], feed_id=feed["id"])) }}" class="{{= "unread" if story["read_status"] == 0 else "read" }}">
+                {{= story["story_title"] }}
+            </a>
+            <p>{{= story["story_date"] }}</p>
+        </div>
+    {{ pass }}
+{{ print time.time() - s }}
+</section>

Index: applications/mobileblur/views/layout.html
==================================================================
--- applications/mobileblur/views/layout.html
+++ applications/mobileblur/views/layout.html
@@ -8,11 +8,11 @@
     <!-- Always force latest IE rendering engine 
 	 (even in intranet) & Chrome Frame 
 	 Remove this if you use the .htaccess -->
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     
-    <title>{{=response.title or request.application}}</title>
+    <title>{{ block title }}{{= " - ".join([response.title, request.application]) }}{{ end }}</title>
     
     <!-- http://dev.w3.org/html5/markup/meta.name.html -->
     <meta name="application-name" content="{{=request.application}}" />	
     
     <!-- Speaking of Google, don't forget to set your site up: 
@@ -23,11 +23,11 @@
 	  j.mp/mobileviewport & davidbcalhoun.com/2010/viewport-metatag 
 	  device-width: Occupy full width of the screen in its current orientation
 	  initial-scale = 1.0 retains dimensions instead of zooming out if page height > device height
 	  maximum-scale = 1.0 retains dimensions instead of zooming in if page width < device width
       -->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
+    <meta name="viewport" content="width=320" />
     
     <!-- Place favicon.ico and apple-touch-icon.png in the root of your domain and delete these references -->
     <link rel="shortcut icon" href="{{=URL('static','favicon.ico')}}" type="image/x-icon">
     <link rel="apple-touch-icon" href="{{=URL('static','favicon.png')}}">
 
@@ -57,10 +57,12 @@
     else: left_sidebar_style = 'style="display: none;"'
     if right_sidebar_enabled: right_sidebar_style = 'style="display: block;"'
     else: right_sidebar_style = 'style="display: none;"'
     style_content = 'style="width: %s"' % width_content
     }}
+<!--    <link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.4.0/bootstrap.min.css">-->
+    <link rel="stylesheet" href="{{= URL("static", "css/1140.css") }}">
   </head>
   
   <!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->	
   <!--[if lt IE 7 ]> <body class="ie6"> <![endif]-->
   <!--[if IE 7 ]>    <body class="ie7"> <![endif]-->
@@ -68,92 +70,39 @@
   <!--[if IE 9 ]>    <body class="ie9"> <![endif]-->
   <!--[if (gt IE 9)|!(IE)]><!--> <body> <!--<![endif]-->
     
     <div class="flash">{{=response.flash or ''}}</div> <!-- notification div -->
     
-    <div id="container">	      		      	
-      
-      <div id="wrapper">		
-	
-	<div id="header"> <!-- header and login nav -->
-	  {{block header}} <!-- this is default header -->
-	  {{try:}}{{=auth.navbar(action=URL('default','user'))}}{{except:pass}}		          
-	  <h1><span id="appname">{{=request.application.capitalize()}}</span>App</h1>
-	  <div style="clear: both;"></div><!-- Clear the divs -->
-	  {{end}}				  					  
-	</div><!-- header  -->
-	
-	<div id="statusbar"><!-- statusbar is menu zone -->
-	  {{block statusbar}} <!-- this is default statusbar -->
-	  {{#------ superfish menu ------}}
-	  {{=MENU(response.menu,_class='sf-menu')}}
-	  <script type="text/javascript">
-	    jQuery(document).ready(function(){
-	    jQuery('ul.sf-menu').superfish();});
-	  </script>
-	  <div style="clear: both;"></div><!-- Clear the divs -->	
-	  {{end}}				
-	</div><!-- statusbar -->
-	
-	<div id="page"> <!-- Here my central body -->	  
-
-	  {{if left_sidebar_enabled:}}
-          <div id="left_sidebar" {{=XML(left_sidebar_style)}} >
-            <div style="padding: 4px;">
-	      {{block left_sidebar}}Content Left Sidebar{{end}}		  
-            </div>
-          </div><!-- left_sidebar -->
-	  {{pass}}
-
-	  <!-- content -->
-	  <div id="content" {{=XML(style_content)}} >
-	    {{include}}	
-	  </div>
-	  <!-- content -->
-
-	  {{if right_sidebar_enabled:}}
-          <div id="right_sidebar" {{=XML(right_sidebar_style)}} >
-            <div style="padding: 4px;">
-              {{block right_sidebar}}Content Right Sidebar{{end}}
-            </div>
-	  </div><!-- right_sidebar -->
-          {{pass}}
-
-
-	  <div style="clear: both;"></div><!-- Clear the divs -->
-	  
-	</div><!-- page -->							
-	
-	<div id="footer">
-	  {{block footer}} <!-- this is default footer -->
-	  <a href="http://www.web2py.com/" style="float: left; padding-right: 6px;">
-	    <img src="{{=URL('static','images/poweredby.png')}}"/>
-	  </a>
-	  {{=T('Copyright')}} &#169; 2010				
-	  <div style="clear: both;"></div><!-- Clear the divs -->
-	  {{end}}
-
-	</div><!-- footer -->			
-      </div><!-- wrapper -->
-    </div><!-- container -->		
+	<header>
+	  {{block header}} <!-- this is default header -->
+          <h1><a href="{{= URL("mobileblur", "default", "index") }}">MobileBlur</a></h1>
+	  {{end}}
+      {{ block header_bonus }}{{end}}
+	</header>
+	
+    <section id="content" class-"container" {{=XML(style_content)}} >
+        {{include}}	
+    </section>
+
+    <footer>
+        <a href="{{= URL("default", "logout") }}">Log out</a>
+    </footer>
     
     <!--[if lt IE 7 ]>
 	<script src="{{=URL('static','js/dd_belatedpng.js')}}"></script>
 	<script> DD_belatedPNG.fix('img, .png_bg'); //fix any <img> or .png_bg background-images </script>
 	<![endif]-->
     
     <!-- asynchronous google analytics: mathiasbynens.be/notes/async-analytics-snippet 
 	 change the UA-XXXXX-X to be your site's ID -->
-    <!--   
 	   <script>
-	     var _gaq = [['_setAccount', 'UA-XXXXX-X'], ['_trackPageview']];
+	     var _gaq = [['_setAccount', 'UA-27222314-1'], ['_trackPageview']];
 	     (function(d, t) {
 	     var g = d.createElement(t),
 	     s = d.getElementsByTagName(t)[0];
 	     g.async = true;
 	     g.src = '//www.google-analytics.com/ga.js';
 	     s.parentNode.insertBefore(g, s);
 	     })(document, 'script');
 	   </script>
-	   -->    
   </body>
 </html>

Index: applications/mobileblur/views/stories/view.html
==================================================================
--- applications/mobileblur/views/stories/view.html
+++ applications/mobileblur/views/stories/view.html
@@ -1,9 +1,13 @@
-{{left_sidebar_enabled=right_sidebar_enabled=False}}
 {{extend 'layout.html'}}
 
-<a href="{{= story["story_permalink"] }}"><h1>{{= story["story_title"] }}</h1></a>
-
-{{= XML(story["story_content"]) }}
-
-{{block left_sidebar}}New Left Sidebar Content{{end}}
-{{block right_sidebar}}New Right Sidebar Content{{end}}
+{{ block header_bonus }}
+    <a href="{{= story["story_permalink"] }}">
+        <h2>{{= story["story_title"] }}</h2>
+    </a>
+    <a href="{{= URL("mark_read", vars=dict(story_id=story["id"], feed_id=feed_id)) }}" class="button">
+        Mark story as read
+    </a>
+{{ end }}
+<section id="story">
+    {{= XML(story["story_content"]) }}
+</section>

ADDED   routes.py
Index: routes.py
==================================================================
--- /dev/null
+++ routes.py
@@ -0,0 +1,166 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# default_application, default_controller, default_function
+# are used when the respective element is missing from the
+# (possibly rewritten) incoming URL
+#
+default_application = 'mobileblur'    # ordinarily set in base routes.py
+default_controller = 'default'  # ordinarily set in app-specific routes.py
+default_function = 'index'      # ordinarily set in app-specific routes.py
+
+# routes_app is a tuple of tuples.  The first item in each is a regexp that will
+# be used to match the incoming request URL. The second item in the tuple is
+# an applicationname.  This mechanism allows you to specify the use of an
+# app-specific routes.py. This entry is meaningful only in the base routes.py.
+#
+# Example: support welcome, admin, app and myapp, with myapp the default:
+
+
+routes_app = ((r'/(?P<app>welcome|admin|app)\b.*', r'\g<app>'),
+              (r'(.*)', r'myapp'),
+              (r'/?(.*)', r'myapp'))
+
+# routes_in is a tuple of tuples.  The first item in each is a regexp that will
+# be used to match the incoming request URL. The second item in the tuple is
+# what it will be replaced with.  This mechanism allows you to redirect incoming
+# routes to different web2py locations
+#
+# Example: If you wish for your entire website to use init's static directory:
+#
+#   routes_in=( (r'/static/(?P<file>[\w./-]+)', r'/init/static/\g<file>') )
+#
+
+routes_in = ((r'.*:/favicon.ico', r'/examples/static/favicon.ico'),
+             (r'.*:/robots.txt', r'/examples/static/robots.txt'),
+             ((r'.*http://otherdomain.com.* (?P<any>.*)', r'/app/ctr\g<any>')))
+
+# routes_out, like routes_in translates URL paths created with the web2py URL()
+# function in the same manner that route_in translates inbound URL paths.
+#
+
+routes_out = ((r'.*http://otherdomain.com.* /app/ctr(?P<any>.*)', r'\g<any>'),
+              (r'/app(?P<any>.*)', r'\g<any>'))
+
+# Error-handling redirects all HTTP errors (status codes >= 400) to a specified
+# path.  If you wish to use error-handling redirects, uncomment the tuple
+# below.  You can customize responses by adding a tuple entry with the first
+# value in 'appName/HTTPstatusCode' format. ( Only HTTP codes >= 400 are
+# routed. ) and the value as a path to redirect the user to.  You may also use
+# '*' as a wildcard.
+#
+# The error handling page is also passed the error code and ticket as
+# variables.  Traceback information will be stored in the ticket.
+#
+# routes_onerror = [
+#     (r'init/400', r'/init/default/login')
+#    ,(r'init/*', r'/init/static/fail.html')
+#    ,(r'*/404', r'/init/static/cantfind.html')
+#    ,(r'*/*', r'/init/error/index')
+# ]
+
+# specify action in charge of error handling
+#
+# error_handler = dict(application='error',
+#                      controller='default',
+#                      function='index')
+
+# In the event that the error-handling page itself returns an error, web2py will
+# fall back to its old static responses.  You can customize them here.
+# ErrorMessageTicket takes a string format dictionary containing (only) the
+# "ticket" key.
+
+# error_message = '<html><body><h1>%s</h1></body></html>'
+# error_message_ticket = '<html><body><h1>Internal error</h1>Ticket issued: <a href="/admin/default/ticket/%(ticket)s" target="_blank">%(ticket)s</a></body></html>'
+
+# specify a list of apps that bypass args-checking and use request.raw_args
+#
+#routes_apps_raw=['myapp']
+#routes_apps_raw=['myapp', 'myotherapp']
+
+def __routes_doctest():
+    '''
+    Dummy function for doctesting routes.py.
+
+    Use filter_url() to test incoming or outgoing routes;
+    filter_err() for error redirection.
+
+    filter_url() accepts overrides for method and remote host:
+        filter_url(url, method='get', remote='0.0.0.0', out=False)
+
+    filter_err() accepts overrides for application and ticket:
+        filter_err(status, application='app', ticket='tkt')
+
+    >>> import os
+    >>> import gluon.main
+    >>> from gluon.rewrite import regex_select, load, filter_url, regex_filter_out, filter_err, compile_regex
+    >>> regex_select()
+    >>> load(routes=os.path.basename(__file__))
+
+    >>> os.path.relpath(filter_url('http://domain.com/favicon.ico'))
+    'applications/examples/static/favicon.ico'
+    >>> os.path.relpath(filter_url('http://domain.com/robots.txt'))
+    'applications/examples/static/robots.txt'
+    >>> filter_url('http://domain.com')
+    '/init/default/index'
+    >>> filter_url('http://domain.com/')
+    '/init/default/index'
+    >>> filter_url('http://domain.com/init/default/fcn')
+    '/init/default/fcn'
+    >>> filter_url('http://domain.com/init/default/fcn/')
+    '/init/default/fcn'
+    >>> filter_url('http://domain.com/app/ctr/fcn')
+    '/app/ctr/fcn'
+    >>> filter_url('http://domain.com/app/ctr/fcn/arg1')
+    "/app/ctr/fcn ['arg1']"
+    >>> filter_url('http://domain.com/app/ctr/fcn/arg1/')
+    "/app/ctr/fcn ['arg1']"
+    >>> filter_url('http://domain.com/app/ctr/fcn/arg1//')
+    "/app/ctr/fcn ['arg1', '']"
+    >>> filter_url('http://domain.com/app/ctr/fcn//arg1')
+    "/app/ctr/fcn ['', 'arg1']"
+    >>> filter_url('HTTP://DOMAIN.COM/app/ctr/fcn')
+    '/app/ctr/fcn'
+    >>> filter_url('http://domain.com/app/ctr/fcn?query')
+    '/app/ctr/fcn ?query'
+    >>> filter_url('http://otherdomain.com/fcn')
+    '/app/ctr/fcn'
+    >>> regex_filter_out('/app/ctr/fcn')
+    '/ctr/fcn'
+    >>> filter_url('https://otherdomain.com/app/ctr/fcn', out=True)
+    '/ctr/fcn'
+    >>> filter_url('https://otherdomain.com/app/ctr/fcn/arg1//', out=True)
+    '/ctr/fcn/arg1//'
+    >>> filter_url('http://otherdomain.com/app/ctr/fcn', out=True)
+    '/fcn'
+    >>> filter_url('http://otherdomain.com/app/ctr/fcn?query', out=True)
+    '/fcn?query'
+    >>> filter_url('http://otherdomain.com/app/ctr/fcn#anchor', out=True)
+    '/fcn#anchor'
+    >>> filter_err(200)
+    200
+    >>> filter_err(399)
+    399
+    >>> filter_err(400)
+    400
+    >>> filter_url('http://domain.com/welcome', app=True)
+    'welcome'
+    >>> filter_url('http://domain.com/', app=True)
+    'myapp'
+    >>> filter_url('http://domain.com', app=True)
+    'myapp'
+    >>> compile_regex('.*http://otherdomain.com.* (?P<any>.*)', '/app/ctr\g<any>')[0].pattern
+    '^.*http://otherdomain.com.* (?P<any>.*)$'
+    >>> compile_regex('.*http://otherdomain.com.* (?P<any>.*)', '/app/ctr\g<any>')[1]
+    '/app/ctr\\\\g<any>'
+    >>> compile_regex('/$c/$f', '/init/$c/$f')[0].pattern
+    '^.*?:https?://[^:/]+:[a-z]+ /(?P<c>\\\\w+)/(?P<f>\\\\w+)$'
+    >>> compile_regex('/$c/$f', '/init/$c/$f')[1]
+    '/init/\\\\g<c>/\\\\g<f>'
+    '''
+    pass
+
+if __name__ == '__main__':
+    import doctest
+    doctest.testmod()
+