diff --git a/Generics/MultiRec/Any.hs b/Generics/MultiRec/Any.hs
deleted file mode 100644
--- a/Generics/MultiRec/Any.hs
+++ /dev/null
@@ -1,17 +0,0 @@
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE GADTs                 #-}
-
-module Generics.MultiRec.Any where
-
-import Generics.MultiRec
-
-data Any phi where
-  Any :: phi ix -> ix -> Any phi
-
--- | Unify an 'Any' with an @a@.
-matchAny :: forall phi ix. EqS phi => phi ix -> Any phi -> Maybe ix
-matchAny p (Any w x) = match' w x p where
-  match' :: EqS s => s b -> b -> s a -> Maybe a
-  match' w x w' = case eqS w w' of
-    Nothing -> Nothing
-    Just Refl -> Just x
diff --git a/Generics/MultiRec/CountIs.hs b/Generics/MultiRec/CountIs.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/CountIs.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE KindSignatures             #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module Generics.MultiRec.CountIs where
+
+import Generics.MultiRec
+
+--------------------------------------------------------------------------------
+-- Count I's (for showing)
+--------------------------------------------------------------------------------
+
+class CountIs (f :: (* -> *) -> * -> *) where
+  countIs :: f r ix -> Int
+
+instance CountIs (I ix)    where countIs _ = 1
+instance CountIs (t :.: f) where countIs _ = 1
+instance CountIs (K a)     where countIs _ = 0
+instance CountIs U         where countIs _ = 0
+
+instance (CountIs f) => CountIs (C c f)    where
+  countIs (_ :: C c f r ix)      = countIs (undefined :: f r ix)
+instance (CountIs f) => CountIs (f :>: ix) where
+  countIs (_ :: (f :>: ix) r xi) = countIs (undefined :: f r ix)
+
+instance (CountIs f, CountIs g) => CountIs (f :+: g) where
+  countIs (L x) = countIs x
+  countIs (R x) = countIs x
+
+instance (CountIs f, CountIs g) => CountIs (f :*: g) where
+  countIs (_ :: (f :*: g) r ix) = countIs (undefined :: f r ix)
+                                + countIs (undefined :: g r ix)
diff --git a/Generics/MultiRec/HZip.hs b/Generics/MultiRec/HZip.hs
deleted file mode 100644
--- a/Generics/MultiRec/HZip.hs
+++ /dev/null
@@ -1,76 +0,0 @@
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE GADTs                 #-}
-
-module Generics.MultiRec.HZip where
-
-import Generics.MultiRec
-import Control.Monad (liftM, liftM2, zipWithM)
-
-class HZip phi f where
-  hzipM :: Monad m =>
-           (forall ix. El phi ix => phi ix -> r ix -> r' ix -> m (r'' ix)) ->
-           f r ix -> f r' ix -> m (f r'' ix)
-
-instance El phi xi => HZip phi (I xi) where
-  hzipM f (I x) (I y) = liftM I (f proof x y)
-
-instance Eq a => HZip phi (K a) where
-  hzipM f (K x) (K y) | x == y    = return (K x)
-                      | otherwise = fail "zip failed in K"
-
-instance HZip phi U where
-  hzipM f U U = return U
-
-instance (HZip phi a, HZip phi b) => HZip phi (a :+: b) where
-  hzipM f (L x) (L y) = liftM L (hzipM f x y)
-  hzipM f (R x) (R y) = liftM R (hzipM f x y)
-  hzipM f _     _     = fail "zip failed"
-
-instance (HZip phi a, HZip phi b) => HZip phi (a :*: b) where
-  hzipM f (x1 :*: y1) (x2 :*: y2) = liftM2 (:*:) (hzipM f x1 x2) (hzipM f y1 y2)
-
-instance HZip phi f => HZip phi (f :>: xi) where
-  hzipM f (Tag x) (Tag y) = liftM Tag (hzipM f x y)
-
-instance HZip phi f => HZip phi (C c f) where
-  hzipM f (C x) (C y) = liftM C (hzipM f x y)
-
-instance HZip phi f => HZip phi ([] :.: f) where
-  hzipM f (D x) (D y) = liftM D (zipWithM (hzipM f) x y)
-
--- | Monadic zip but argument is not monadic
-hzip :: (HZip phi f, Monad m) =>
-        (forall ix. El phi ix => phi ix -> r ix -> s ix -> t ix) ->
-        phi ix -> f r ix -> f s ix -> m (f t ix)
-hzip f p = hzipM (\w x y -> return (f w x y))
-
--- | Unsafe zip
-hzip' :: (HZip phi f) =>
-         (forall ix. El phi ix => phi ix -> r ix -> s ix -> t ix) ->
-         phi ix -> f r ix -> f s ix -> f t ix
-hzip' f p a b = case hzip (\p x y -> f p x y) p a b of
-  Nothing  -> error "generic zip failed"
-  Just res -> res
-
--- | Combine two structures monadically only
-combine :: forall phi f r r' m ix. (Monad m, HZip phi f) =>
-           (forall ix. El phi ix => phi ix -> r ix -> r' ix -> m ()) ->
-           phi ix -> f r ix -> f r' ix -> m ()
-combine f l x y = hzipM wrapf x y >> return ()
-  where
-    wrapf :: forall ix' b. El phi ix' => phi ix' -> r ix' -> r' ix' -> m (K0 () b)
-    wrapf ix x y = f ix x y >> return (K0 ())
-
--- | Generic equality
-geq :: (Fam phi, HZip phi (PF phi)) => phi ix -> ix -> ix -> Bool
-geq ix x y = maybe False (const True) (geq' ix (I0 x) (I0 y))
-
--- | Monadic generic equality (just for the sake of the monad!)
-geq' :: (Monad m, Fam phi, HZip phi (PF phi))
-        => phi ix -> I0 ix -> I0 ix -> m ()
-geq' p (I0 x) (I0 y) = combine geq' p (from p x) (from p y)
diff --git a/Generics/MultiRec/LR.hs b/Generics/MultiRec/LR.hs
deleted file mode 100644
--- a/Generics/MultiRec/LR.hs
+++ /dev/null
@@ -1,94 +0,0 @@
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE GADTs                 #-}
-
-module Generics.MultiRec.LR where
-
-import Generics.MultiRec
-
------------------------------------------------------------------------------
--- Functions for generating values that are different on top-level.
------------------------------------------------------------------------------
-
--- | The @LRBase@ class defines two functions, @leftb@ and @rightb@, which 
--- should produce different values.
-class LRBase a where
-  leftb  :: a
-  rightb :: a
-
-instance LRBase Int where
-  leftb  = 0
-  rightb = 1
-
-instance LRBase Integer where
-  leftb  = 0
-  rightb = 1
-
-instance LRBase Char where
-  leftb  = 'L'
-  rightb = 'R'
- 
-instance LRBase Bool where
-  leftb  = True
-  rightb = False
-
-instance LRBase a => LRBase [a] where
-  leftb  = []
-  rightb = [rightb]
-
--- | The @LR@ class defines two functions, @leftf@ and @rightf@, which should 
--- produce different functorial values.
-class LR phi (f :: (* -> *) -> * -> *) where
---    leftf  :: s ix -> (forall ix . Ix s ix => s ix -> r ix) -> [f s r ix]
-  leftf  :: phi ix -> (forall ix'. El phi ix' => phi ix' -> r ix') -> [f r ix]
-  rightf :: phi ix -> (forall ix'. El phi ix' => phi ix' -> r ix') -> [f r ix]
- 
-instance El phi xi => LR phi (I xi) where
-  leftf  _ f = [I (f proof)]
-  rightf _ f = [I (f proof)]
-
-instance LRBase a => LR phi (K a) where
-  leftf  _ _ = [K leftb]
-  rightf _ _ = [K rightb]
-
-instance LR phi U where
-  leftf  _ _ = [U]
-  rightf _ _ = [U]
-
-instance (LR phi f, LR phi g) => LR phi (f :+: g) where
-  leftf  p f = map L (leftf  p f) ++ map R (leftf  p f)
-  rightf p f = map R (rightf p f) ++ map L (rightf p f)
-
-instance (LR phi f, LR phi g) => LR phi (f :*: g) where
-  leftf  p f = zipWith (:*:) (leftf  p f) (leftf  p f)
-  rightf p f = zipWith (:*:) (rightf p f) (rightf p f)
-
-instance LR phi f => LR phi (C c f) where
-  leftf  p f = map C (leftf  p f)
-  rightf p f = map C (rightf p f)
-
-instance (El phi ix, LR phi f, EqS phi) => LR phi (f :>: ix) where
-  leftf  p f = case eqS (proof :: phi ix) p of
-    Just Refl -> map Tag (leftf  p f)
-    Nothing   -> []
-  rightf p f = case eqS (proof :: phi ix) p of
-    Just Refl -> map Tag (rightf  p f)
-    Nothing   -> []
-
-instance LR phi f => LR phi ([] :.: f) where
-  leftf  p f = [D []]
-  rightf p f = map (\v -> D [v]) $ rightf p f
-
-left :: (Fam phi, LR phi (PF phi)) => phi ix -> ix
-left p = to p $ safeHead $ leftf p (I0 . left)
-
-right :: (Fam phi, LR phi (PF phi)) => phi ix -> ix
-right p = to p $ safeHead $ rightf p (I0 . right)
-
-safeHead [] = error "Internal error, left or right returned []"
-safeHead (x:xs) = x
diff --git a/Generics/MultiRec/Ord.hs b/Generics/MultiRec/Ord.hs
deleted file mode 100644
--- a/Generics/MultiRec/Ord.hs
+++ /dev/null
@@ -1,57 +0,0 @@
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE FlexibleContexts      #-}
-
-module Generics.MultiRec.Ord where
-
-import Generics.MultiRec
-import Data.Monoid (mappend)
-
---------------------------------------------------------------------------------
--- Generic Ord
---------------------------------------------------------------------------------
-class HOrd phi f where
-  hcompare :: (forall ix. phi ix -> r ix -> r ix -> Ordering) 
-              -> phi ix -> f r ix -> f r ix -> Ordering
-
-instance El phi xi => HOrd phi (I xi) where
-  hcompare f _ (I x) (I y) = f proof x y
-
-instance Ord a => HOrd phi (K a) where
-  hcompare _ _ (K x) (K y) = compare x y
-
-instance HOrd phi U where
-  hcompare _ _ U U = EQ
-
-instance (HOrd phi f, HOrd phi g) => HOrd phi (f :+: g) where
-  hcompare f p (L _) (R _) = LT
-  hcompare f p (R _) (L _) = GT
-  hcompare f p (L x) (L y) = hcompare f p x y
-  hcompare f p (R x) (R y) = hcompare f p x y
-
-instance (HOrd phi f, HOrd phi g) => HOrd phi (f :*: g) where
-  hcompare f p (v :*: x) (w :*: y) = hcompare f p v w `mappend` hcompare f p x y
-
-instance HOrd phi f => HOrd phi (C c f) where
-  hcompare f p (C x) (C y) = hcompare f p x y
-
-instance HOrd phi f => HOrd phi (f :>: ix) where
-  hcompare f p (Tag x) (Tag y) = hcompare f p x y
-
-instance (Ord1 f, HOrd phi g) => HOrd phi (f :.: g) where
-  hcompare f p (D x) (D y) = compare1 (hcompare f p) x y
-
-class Ord1 f where
-  compare1 :: (a -> a -> Ordering) -> f a -> f a -> Ordering
-
-instance Ord1 [] where
-  compare1 f [] [] = EQ
-  compare1 f [] _  = LT
-  compare1 f _  [] = GT
-  compare1 f (x:xs) (y:ys) = f x y `mappend` compare1 f xs ys
-
-gcompare :: (Fam phi, HOrd phi (PF phi)) => phi ix -> ix -> ix -> Ordering
-gcompare p x1 x2 = hcompare (\ p (I0 x1) (I0 x2) -> gcompare p x1 x2) p (from p x1) (from p x2)
diff --git a/Generics/MultiRec/Rewriting.hs b/Generics/MultiRec/Rewriting.hs
deleted file mode 100644
--- a/Generics/MultiRec/Rewriting.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Generics.MultiRec.Rewriting (
-  module Generics.MultiRec.Rewriting.Machinery,
-  module Generics.MultiRec.Rewriting.Rules,
-) where
-
-import Generics.MultiRec.Rewriting.Machinery
-import Generics.MultiRec.Rewriting.Rules
diff --git a/Generics/MultiRec/Rewriting/Machinery.hs b/Generics/MultiRec/Rewriting/Machinery.hs
deleted file mode 100644
--- a/Generics/MultiRec/Rewriting/Machinery.hs
+++ /dev/null
@@ -1,66 +0,0 @@
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE UndecidableInstances  #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE GADTs                 #-}
-
-module Generics.MultiRec.Rewriting.Machinery where
-
-import Generics.MultiRec
-import Generics.MultiRec.HZip
-import Generics.MultiRec.Rewriting.Rules
-import Generics.MultiRec.Any
-
-import qualified Data.Map as M
-import Control.Monad.State
-
------------------------------------------------------------------------------
--- Class synonym for shorter names
------------------------------------------------------------------------------
-class (Fam phi, EqS phi, HZip phi (PF phi), HFunctor phi (PF phi))
-      => Rewrite phi
-
------------------------------------------------------------------------------
--- Actual rewriting
------------------------------------------------------------------------------
-rewriteM :: Rewrite phi => Rule phi a -> a -> Maybe a
-rewriteM (Rule p (lhs :~> rhs)) term = 
-  match p lhs term >>= return . (\s -> inst s p rhs)
-
-match :: (Monad m, Rewrite phi) => 
-         phi ix -> Scheme phi ix -> ix -> m (Subst phi)
-match p pat term = execStateT (matchM p pat (I0 term)) M.empty
-
-matchM :: (Monad m, Rewrite phi) 
-          => phi ix -> Scheme phi ix -> I0 ix -> StateT (Subst phi) m ()
-matchM p scheme (I0 e) = case scheme of
-  HIn (L (K var)) -> do 
-    subst <- get
-    case M.lookup var subst of
-      Nothing     -> put (M.insert var (Any p e) subst)
-      Just exTerm -> checkEqual p e exTerm
-  HIn (R r) -> combine matchM p r (from p e)
-
-checkEqual :: (Monad m, Rewrite phi)
-           => phi ix -> ix -> Any phi -> m ()
-checkEqual p e (Any p' e') = case eqS p p' of
-  Nothing   -> fail "checkEqual"
-  Just Refl -> geq' p (I0 e) (I0 e')
-
-inst :: Rewrite phi =>
-        Subst phi -> phi ix -> Scheme phi ix -> ix
-inst s ix p
-  = case p of
-     HIn (L (K x)) ->
-        case M.lookup x s of
-          Just (Any ix' e)
-            -> case eqS ix ix' of
-                 Just Refl -> e
-                 Nothing -> error "Coerce error in inst"
-     HIn (R r) -> to ix $ hmap (\ix' -> I0 . inst s ix') ix r
-
-type Subst phi = M.Map Metavar (Any phi)
diff --git a/Generics/MultiRec/Rewriting/Rules.hs b/Generics/MultiRec/Rewriting/Rules.hs
deleted file mode 100644
--- a/Generics/MultiRec/Rewriting/Rules.hs
+++ /dev/null
@@ -1,100 +0,0 @@
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE UndecidableInstances  #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE GADTs                 #-}
-
-module Generics.MultiRec.Rewriting.Rules where
-
-import Generics.MultiRec
-import Generics.MultiRec.LR
-import Generics.MultiRec.HZip
-
------------------------------------------------------------------------------
--- Rule specification.
------------------------------------------------------------------------------
-
--- | Specifies a rule as a value of a datatype.
-infix 5 :~>
-data RuleSpec a = a :~> a
-
--- | Returns the left-hand side of a rule.
-lhsR :: RuleSpec a -> a
-lhsR (x :~> _) = x
-
--- | Returns the right-hand side of a rule.
-rhsR :: RuleSpec a -> a
-rhsR (_ :~> y) = y
-
------------------------------------------------------------------------------
--- Representation of a rule.
------------------------------------------------------------------------------
--- | Extends a pattern functor with a case for a metavariable.
-type Ext phi  = K Metavar :+: PF phi
-type Metavar  = Int
-
--- | Recursively extends a type with a case for a metavariable.
-type Scheme phi = HFix (Ext phi)
-
--- | Allows metavariables on either side of a rule.
-data Rule phi a where 
-  Rule :: phi ix -> RuleSpec (Scheme phi ix) -> Rule phi ix
-
--- | Constructs a metavariable.
-metavar :: phi ix -> Metavar -> Scheme phi ix
-metavar _ = HIn . L . K
-
-pf :: phi ix -> PF phi (Scheme phi) ix -> Scheme phi ix
-pf _ = HIn . R
-
------------------------------------------------------------------------------
--- Builder for transforming a rule specification to a rule.
------------------------------------------------------------------------------
-
-class Builder phi a where
-  type Target a :: *
-  base          :: phi (Target a) -> a -> RuleSpec (Target a)
-  diag          :: phi (Target a) -> a -> [RuleSpec (Target a)]
-
-instance Builder phi (RuleSpec a) where
-  type Target (RuleSpec a) = a
-  base _ x                 = x
-  diag _ x                 = [x]
-
-instance (Builder phi a, Fam phi, LR phi (PF phi), El phi b)
-         => Builder phi (b -> a) where
-  type Target (b -> a) = Target a
-  base ix f            = base ix (f (left  (proof :: phi b)))
-  diag ix f            = base ix (f (right (proof :: phi b))) :
-                         diag ix (f (left  (proof :: phi b)))
-
-rule :: forall phi r. (Fam phi, Builder phi r, HZip phi (PF phi), 
-                       El phi (Target r), EqS phi, HFunctor phi (PF phi))
-        => r -> Rule phi (Target r)
-rule f = Rule ix $ foldr1 mergeRules rules
-  where
-    ix = proof :: phi (Target r)
-    mergeRules x y = 
-      mergeSchemes ix (lhsR x) (lhsR y) :~>
-      mergeSchemes ix (rhsR x) (rhsR y)
-    rules          = zipWith (ins (base ix f)) (diag ix f) [0..]   
-    ins x y v      = 
-      insertMVar v ix (I0 (lhsR x)) (I0 (lhsR y)) :~>
-      insertMVar v ix (I0 (rhsR x)) (I0 (rhsR y))
-
-mergeSchemes :: HZip phi (PF phi)
-                => phi ix -> Scheme phi ix -> Scheme phi ix -> Scheme phi ix
-mergeSchemes p a@(HIn x) b@(HIn y) = case (x,y) of
-  (L _,_) -> a
-  (_,L _) -> b
-  _       -> HIn (hzip' mergeSchemes p x y)
-
-insertMVar :: forall phi ix. (Fam phi, HZip phi (PF phi), El phi ix)
-              => Metavar -> phi ix -> I0 ix -> I0 ix -> Scheme phi ix
-insertMVar name p (I0 x) (I0 y) =
-  case hzip (insertMVar name) p (from p x) (from p y) of
-    Just struc -> pf p struc
-    Nothing    -> metavar p name
diff --git a/Generics/MultiRec/ShallowEq.hs b/Generics/MultiRec/ShallowEq.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/ShallowEq.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE KindSignatures             #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module Generics.MultiRec.ShallowEq where
+
+import Generics.MultiRec
+import Data.Foldable ( toList )
+import Data.Traversable ( Traversable )
+
+--------------------------------------------------------------------------------
+-- Shallow equality
+--------------------------------------------------------------------------------
+
+class SEq phi (f :: (* -> *) -> * -> *) where
+  shallowEq :: phi ix -> f r ix  -> f r ix -> Bool
+
+instance SEq phi (I xi) where
+  shallowEq _ _ _ = True
+
+instance SEq phi U where
+  shallowEq _ _ _ = True
+
+instance Eq a => SEq phi (K a) where
+  shallowEq p (K a) (K b) = a == b
+
+instance (SEq phi f, SEq phi g) => SEq phi (f :+: g) where
+  shallowEq p (L a) (L b) = shallowEq p a b
+  shallowEq p (R a) (R b) = shallowEq p a b
+  shallowEq _ _     _     = False
+
+instance (SEq phi f, SEq phi g) => SEq phi (f :*: g) where
+  shallowEq p (a :*: b) (c :*: d) = shallowEq p a c && shallowEq p b d
+
+instance SEq phi f => SEq phi (f :>: ix) where
+  shallowEq p (Tag a) (Tag b) = shallowEq p a b
+
+instance SEq phi f => SEq phi (C c f) where
+  shallowEq p (C a) (C b) = shallowEq p a b
+
+instance (Traversable t, Eq (t ()), SEq phi f) => SEq phi (t :.: f) where
+  shallowEq p (D a) (D b) = fmap (const ()) a == fmap (const ()) b
+                            && and (zipWith (shallowEq p) (toList a) (toList b))
diff --git a/Generics/MultiRec/Transformations/Children.hs b/Generics/MultiRec/Transformations/Children.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Transformations/Children.hs
@@ -0,0 +1,80 @@
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE OverlappingInstances       #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module Generics.MultiRec.Transformations.Children where
+
+import Generics.MultiRec hiding ( show, foldM )
+import Data.Foldable ( toList )
+
+import Generics.MultiRec.CountIs
+import Generics.MultiRec.Transformations.Path
+
+--------------------------------------------------------------------------------
+-- Children
+--------------------------------------------------------------------------------
+
+-- | Get all children with their paths
+allChildren :: forall phi ix xi. (Fam phi, Children phi (PF phi) xi)
+            => phi ix -> phi xi -> ix -> [(Path phi xi ix, xi)]
+allChildren p1 p2 = map (\(p,x) -> (p, unI0 x)) . children f p1 p2 (\w z -> Push w z Empty) . from p1 where
+  f :: forall ix'. phi ix' -> phi xi -> (Path phi ix' ix) -> I0 ix'
+    -> [(Path phi xi ix, I0 xi)]
+  f p1' p2' w (I0 y) = map (\(w', x) -> (w <.> w', I0 x)) $ allChildren p1' p2' y
+
+class Children phi (f :: (* -> *) -> * -> *) xi where
+  children :: (forall ix'. phi ix' -> phi xi
+                 -> Path phi ix' ix
+                 -> r ix' -> [(Path phi xi ix,r xi)])
+           -> phi ix -> phi xi -> (forall xi. phi xi -> Dir f xi ix -> Path phi xi ix)
+             -> f r ix -> [(Path phi xi ix, r xi)]
+
+instance (Fam phi, El phi ix)            => Children phi (I ix) ix where
+  children f p1 p2 w (I r) = (w p2 CId, r) : f proof proof (w p2    CId) r
+
+instance (Fam phi, El phi ix, El phi xi) => Children phi (I xi) ix where
+  children f p1 p2 w (I r) =                 f proof proof (w proof CId) r
+
+instance Children phi (K a) ix where
+  children _ _ _ _ _ = []
+
+instance Children phi U ix where
+  children _ _ _ _ _ = []
+
+instance (Children phi f ix, Children phi g ix) => Children phi (f :+: g) ix where
+  children f p1 p2 w (L x) = children f p1 p2 (\w' -> w w' . CL) x
+  children f p1 p2 w (R x) = children f p1 p2 (\w' -> w w' . CR) x
+
+instance (Children phi f ix, Children phi g ix, CountIs g)
+    => Children phi (f :*: g) ix where
+  children f p1 p2 w (x :*: y) =    children f p1 p2 (\w' z -> w w' (C1 z nullY)) x
+                                 ++ children f p1 p2 (\w' z -> w w' (C2 nullX z)) y
+    where nullX = error "nullX" -- fmap (const ()) x
+          nullY = error "nullY" -- fmap (const ()) y
+
+instance (Constructor c, Children phi f ix) => Children phi (C c f) ix where
+  children f p1 p2 w (C x) = children f p1 p2 (\w' -> w w' . CC) x
+
+instance Children phi f ix => Children phi (f :>: xi) ix where
+  children f p1 p2 w (Tag x) = children f p1 p2 (\w' -> w w' . CTag) x
+
+{-
+instance (Traversable t, Children phi f ix) => Children phi (t :.: f) ix where
+ children f p1 p2 w (D x) = concatMap (\(i,x) -> children f p1 p2 (w . TrvI i) x)
+                            $ zip [0..] (toList x)
+-}
+
+instance (Children phi f ix) => Children phi (Maybe :.: f) ix where
+ children f p1 p2 w (D x) = concatMap (children f p1 p2 (\w' -> w w' . CCM)) . toList $ x
+
+instance (Children phi f ix) => Children phi ([] :.: f) ix where
+ children f p1 p2 w (D x) = concatMap (\(i,x) -> children f p1 p2 (\w' z -> w w' (CCL (ll i) z lr)) x)
+                            $ zip [0..] x
+      where ll i = replicate i (error "oops4")
+            lr = error "oops5"
diff --git a/Generics/MultiRec/Transformations/Explicit.hs b/Generics/MultiRec/Transformations/Explicit.hs
deleted file mode 100644
--- a/Generics/MultiRec/Transformations/Explicit.hs
+++ /dev/null
@@ -1,442 +0,0 @@
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE FlexibleContexts      #-}
-{-# LANGUAGE UndecidableInstances  #-}
-{-# LANGUAGE ScopedTypeVariables   #-}
-
-module Generics.MultiRec.Transformations.Explicit (
-  diff, apply, Transformation, AnyInsert (..), WithRef (..), Path, 
-  Transform, OrdI (..),
-  HasRef (..), NiceTransformation, NiceInsert (..),
-  toNiceTransformation, fromNiceTransformation
-  ) where
-
-import Generics.MultiRec.Any
-import Generics.MultiRec.Eq
-import Generics.MultiRec.Ord
-
-import Generics.MultiRec hiding (show, foldM)
-import Control.Applicative ( (<|>) )
-import Control.Monad (foldM)
-import Control.Monad.State hiding (foldM)
-import Data.Monoid (mappend)
-import qualified Data.Map as Map
-import Data.Map (Map)
-
---------------------------------------------------------------------------------
--- Paths, annotations, edits and existentials
---------------------------------------------------------------------------------
-data WithRef phi f a = InR (PF phi f a)
-                     | Ref Path
-
-type Path = [Int]
-
-data AnyInsert phi where
-  AnyInsert :: phi ix -> Path -> HFix (WithRef phi) ix -> AnyInsert phi
-
-type Transformation phi = [ AnyInsert phi]
-
-class (Fam phi, Children phi (PF phi), CountI phi (PF phi),
-       HFunctor phi (PF phi), SEq phi (PF phi), ExtractN phi (PF phi), 
-       MapN phi (PF phi), EqS phi, HEq phi (PF phi), HOrd phi (PF phi),
-       OrdI phi) => Transform phi
-
---------------------------------------------------------------------------------
--- Applying
---------------------------------------------------------------------------------
--- | Apply the transformation to the given tree
-apply :: forall phi ix. (Transform phi)
-         => phi ix -> ix -> Transformation phi -> Maybe ix
-apply p t = foldM (apply' p) t where
-  apply' :: forall ix. phi ix -> ix -> AnyInsert phi -> Maybe ix
-  apply' p' _ (AnyInsert p'' [] c) = case eqS p' p'' of 
-    Just Refl -> lookupRefs p t p' c
-    Nothing   -> Nothing
-  apply' p' a (AnyInsert p'' (i:is) c) =
-    liftM (to p') $ tmapN f p' $ from p' a where
-      f :: forall ix. Int -> phi ix -> I0 ix -> Maybe (I0 ix)
-      f j p''' x | i == j    = liftM I0 (apply' p''' (unI0 x) (AnyInsert p'' is c))
-                 | otherwise = return x
-
--- | Look up the references using the original structure
-lookupRefs :: forall phi ix ix'. (Fam phi, HFunctor phi (PF phi), ExtractN phi (PF phi), EqS phi) 
-              => phi ix -> ix -> phi ix' -> HFix (WithRef phi) ix' -> Maybe ix'
-lookupRefs p r p' = build .  hout where
-  build :: WithRef phi (HFix (WithRef phi)) ix' -> Maybe ix'
-  build (InR x) = liftM (to p') (hmapM (\p'' -> liftM I0 . lookupRefs p r p'') p' x)
-  build (Ref l) = extract l p r >>= matchAny p'
-
--- | Extract the subtree at the given path
-extract :: (Fam phi, ExtractN phi (PF phi)) => Path -> phi ix -> ix -> Maybe (Any phi)
-extract []     p a = return $ Any p a
-extract (i:is) p a = extractN i p a >>= \(Any p' x) -> extract is p' x
-
---------------------------------------------------------------------------------
--- Memoisation
---------------------------------------------------------------------------------
--- | Comparing index of different types
-class OrdI phi where
-  compareI :: phi ix -> phi ix' -> Ordering
-  compareI p1 p2 = compare (indexI p1) (indexI p2)
-  indexI :: phi ix -> Int
-  indexI = error "At least compareI or indexI should be implemented."
-
--- | Key used in memoisation table
-data MemoKey phi where
-  MemoKey :: phi ix -> Bool -> ix -> ix -> MemoKey phi
-
-instance (EqS phi, Fam phi, HEq phi (PF phi)) => Eq (MemoKey phi) where
-  (MemoKey p1 a1 b1 c1) == (MemoKey p2 a2 b2 c2) = case eqS p1 p2 of
-    Nothing   -> False
-    Just Refl -> a1 == a2 && eq p1 b1 b2 && eq p1 c1 c2
-
-instance (EqS phi, Fam phi, OrdI phi, HEq phi (PF phi), HOrd phi (PF phi))
-         => Ord (MemoKey phi) where
-  compare (MemoKey p1 a1 b1 c1) (MemoKey p2 a2 b2 c2) = case eqS p1 p2 of
-    Nothing   -> compareI p1 p2
-    Just Refl -> compare a1 a2 `mappend` gcompare p1 b1 b2 
-                               `mappend` gcompare p1 c1 c2
-
--- | The type of the memo table
-type MemoTable phi = Map (MemoKey phi) (Transformation phi)
-type Memo phi a = State (MemoTable phi) a
-
-runMemo :: Memo phi a -> a
-runMemo = flip evalState Map.empty
-
-recMemo :: (Fam phi, HEq phi (PF phi), HOrd phi (PF phi), EqS phi, OrdI phi) => 
-           (forall ix. Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi))
-           -> Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi)
-recMemo f a p b c = do
-  mp <- get
-  let k = MemoKey p a b c
-  case Map.lookup k mp of
-    Just r -> return r
-    Nothing -> do
-      r <- f a p b c
-      modify (Map.insert k r)
-      return r
-
---------------------------------------------------------------------------------
--- Diffing
---------------------------------------------------------------------------------
--- | Find a set of insertions to transform the first into the second tree
-diff :: forall phi ix. (Transform phi)
-        => phi ix -> ix -> ix -> Transformation phi
-diff p a b = runMemo (build False p a b)
-  where
-    childPaths :: [(Any phi, Path)]
-    childPaths = childrenPaths p a
-    build :: forall ix. Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi)
-    build False p' a' b' | eq p' a' b' = return []
-    build ins   p' a' b' = case anyLookup p' b' childPaths of
-      Just l  -> return [ AnyInsert p' [] (HIn $ Ref l) ]
-      Nothing -> uses >>= maybe insert return -- Only insert when we cannot reuse
-        where
-          -- Construct the edits for the children based on a root
-          construct :: Bool -> ix -> Memo phi (Maybe (Transformation phi))
-          construct ins' c = 
-            if shallowEq p' (from p' c) (from p' b')
-            then do r <- zipWithM (\(Any p1 c1) (Any p2 c2) -> case eqS p1 p2 of
-                                      Just Refl -> recMemo build ins' p1 c1 c2)
-                         (imChildren p' c) (imChildren p' b')
-                    return $ Just $ concat $ updateChildPaths r
-            else return Nothing
-          -- Possible edits reusing the existing tree or using a part of
-          -- the original tree. The existing tree is only used if we didn't
-          -- just insert it, since we want to keep the inserts small
-          uses :: Memo phi (Maybe (Transformation phi))
-          uses = reuses >>= \re -> case re of
-              Just r | ins -> return re
-              _            -> construct ins a' >>= return . pickBest re
-          -- Possible edits that include reusing a part of the original tree
-          reuses :: Memo phi (Maybe (Transformation phi))
-          reuses = foldM f Nothing childPaths where
-            addRef :: Path -> Maybe (Transformation phi) 
-                       -> Maybe (Transformation phi)
-            addRef l = liftM ((AnyInsert p' [] (HIn $ Ref l)):)
-            f c (Any p'' x, l) = case eqS p' p'' of
-              Just Refl -> construct False x >>= return . pickBest c . addRef l
-              Nothing   -> return c
-          -- Best edit including insertion, only chosen if nothing can be reused
-          insert :: Memo phi (Transformation phi)
-          insert = do
-            Just r <- construct True b'
-            let (r',e')  = partialApply p' (annotate p' b') r
-            return $ (AnyInsert p' [] r') : e'
-
--- | Pick the best edit
-pickBest :: Maybe (Transformation phi) -> Maybe (Transformation phi) -> Maybe (Transformation phi)
-pickBest e1 e2 = case (e1,e2) of
-  (Just e1', Just e2') -> Just (pickShortest e1' e2')
-  _                    -> e1 <|> e2
-
--- | Pick the shortest of two lists lazily
-pickShortest :: [a] -> [a] -> [a]
-pickShortest a b = if f a b then a else b
-  where f []     _      = True
-        f _      []     = False
-        f (_:xs) (_:ys) = f xs ys
-
--- | Lookup with a specific type
-anyLookup :: (Fam phi, EqS phi, HEq phi (PF phi))
-             => phi ix -> ix -> [(Any phi, a)] -> Maybe a
-anyLookup p _ [] = Nothing
-anyLookup p x ((Any p' y,r) : ys) = case eqS p p' of
-  Just Refl | eq p x y -> Just r
-  _                    -> anyLookup p x ys
-
--- | Lift a tree to an edit structure
-annotate :: (Fam phi, HFunctor phi (PF phi)) => phi ix -> ix -> HFix (WithRef phi) ix
-annotate p = HIn . InR . hmap (\p' (I0 x) -> annotate p' x) p . from p
-
--- | Extend the paths of edits for the children with the child number
-updateChildPaths :: [Transformation phi] -> [Transformation phi]
-updateChildPaths = zipWith (\n -> map (\(AnyInsert p l c) -> (AnyInsert p (n:l) c))) [0..]
-
--- | Try to apply as much edits to the edit structure as possible
---   to make the final edit smaller
-partialApply :: (Fam phi, CountI phi (PF phi), ExtractN phi (PF phi), MapN phi (PF phi), EqS phi)
-                => phi ix -> HFix (WithRef phi) ix -> Transformation phi -> (HFix (WithRef phi) ix, Transformation phi)
-partialApply _ a [] = (a, [])
-partialApply p a (AnyInsert p' l x : xs) = case replace p' l x p a of
-  Just a' -> partialApply p a' xs
-  Nothing -> let (a',xs') = partialApply p a xs in (a', AnyInsert p' l x : xs')
-
--- | Replace a subtree in an edit structure
-replace :: forall phi ix ix'. (Fam phi, EqS phi, MapN phi (PF phi))
-           => phi ix -> Path -> HFix (WithRef phi) ix
-           -> phi ix' -> HFix (WithRef phi) ix' -> Maybe (HFix (WithRef phi) ix')
-replace p [] r p' _ = case eqS p p' of
-  Just Refl -> Just r
-  Nothing   -> Nothing
-replace p (i:is) r p' a = case hout a of
-  Ref _  -> Nothing
-  InR a' -> liftM HIn . liftM InR . tmapN f p' $ a'
-    where f :: forall ix. Int -> phi ix -> HFix (WithRef phi) ix -> Maybe (HFix (WithRef phi) ix)
-          f j p'' = if i == j then replace p is r p'' else Just
-
---------------------------------------------------------------------------------
--- Shallow equality
---------------------------------------------------------------------------------
-
-class SEq phi (f :: (* -> *) -> * -> *) where
-  shallowEq :: phi ix -> f r ix  -> f r ix -> Bool
-
-instance El phi xi => SEq phi (I xi) where
-  shallowEq _ (I _) (I _) = True
-
-instance SEq phi U where
-  shallowEq _ U U = True
-
-instance Eq a => SEq phi (K a) where
-  shallowEq p (K a) (K b) = a == b
-
-instance (SEq phi f, SEq phi g) => SEq phi (f :+: g) where
-  shallowEq p (L a) (L b) = shallowEq p a b
-  shallowEq p (R a) (R b) = shallowEq p a b
-  shallowEq _ _     _     = False
-
-instance (SEq phi f, SEq phi g) => SEq phi (f :*: g) where
-  shallowEq p (a :*: b) (c :*: d) = shallowEq p a c && shallowEq p b d
-
-instance SEq phi f => SEq phi (f :>: ix) where
-  shallowEq p (Tag a) (Tag b) = shallowEq p a b
-
-instance SEq phi f => SEq phi (C c f) where
-  shallowEq p (C a) (C b) = shallowEq p a b
-
--- Todo: is this the best choice?
-instance SEq phi ([] :.: ix) where
-  shallowEq p (D a) (D b) = length a == length b
-
---------------------------------------------------------------------------------
--- ExtractN
---------------------------------------------------------------------------------
-
-extractN :: (Fam phi, ExtractN phi (PF phi), Monad m) 
-            => Int -> phi ix -> ix -> m (Any phi)
-extractN i p v = extractN' (\p (I0 v) -> Any p v) i p (from p v)
-
-class ExtractN phi (f :: (* -> *) -> * -> *) where
-  extractN' :: Monad m => (forall ix. phi ix -> r ix -> r')
-                          -> Int -> phi ix -> f r ix -> m r'
-
-instance El phi xi => ExtractN phi (I xi) where
-  extractN' mka 0 _ (I r) = return $ mka proof r
-  extractN' _   _ _ (I _) = fail "extractN"
-
-instance ExtractN phi (K a) where
-  extractN' mka _ _ (K _) = fail "extractN"
-
-instance ExtractN phi U where
-  extractN' mka _ _ U = fail "extractN"
-
-instance (ExtractN phi f, ExtractN phi g) => ExtractN phi (f :+: g) where
-  extractN' mka i p (L x) = extractN' mka i p x
-  extractN' mka i p (R x) = extractN' mka i p x
-
-instance (CountI phi f, ExtractN phi f, ExtractN phi g) => ExtractN phi (f :*: g) where
-  extractN' mka i p (x :*: y) = let n = countI p x
-                                in if i < n then extractN' mka i     p x
-                                            else extractN' mka (i-n) p y
-
-instance ExtractN phi f => ExtractN phi (f :>: ix) where
-  extractN' mka i p (Tag x) = extractN' mka i p x
-
-instance ExtractN phi f => ExtractN phi (C c f) where
-  extractN' mka i p (C x) = extractN' mka i p x
-
--- Todo: is this the best choice?
-instance ExtractN phi f => ExtractN phi ([] :.: f) where
-  extractN' mka i p (D x) = extractN' mka 0 p (x !! i)
-
---------------------------------------------------------------------------------
--- MapN
---------------------------------------------------------------------------------
-
--- | Map a function with child index at a top-level structure
-tmapN :: (Fam phi, MapN phi f, Monad m)
-         => (forall ix. Int -> phi ix -> r ix -> m (r' ix))
-         -> phi ix -> f r ix -> m (f r' ix)
-tmapN = mapN 0
-
-class MapN phi (f :: (* -> *) -> * -> *) where
-  mapN :: Monad m => Int -> (forall ix. Int -> phi ix -> r ix -> m (r' ix))
-                           -> phi ix -> f r ix -> m (f r' ix)
-
-instance El phi xi => MapN phi (I xi) where
-  mapN i f p (I x) = liftM I (f i proof x)
-
-instance MapN phi (K a) where
-  mapN _ _ _ (K x)  = return $ K x
-
-instance MapN phi U where
-  mapN _ _ _ U = return U
-
-instance (MapN phi f, MapN phi g) => MapN phi (f :+: g) where
-  mapN i f p (L x) = liftM L (mapN i f p x)
-  mapN i f p (R x) = liftM R (mapN i f p x)
-
--- Here we increment our parameter. Does not require right-nested products
-instance (CountI phi f, MapN phi f, MapN phi g) => MapN phi (f :*: g) where
-  mapN i f p (x :*: y) = liftM2 (:*:) (mapN i f p x) (mapN (i + countI p x) f p y)
-
-instance MapN phi f => MapN phi (f :>: ix) where
-  mapN i f p (Tag x) = liftM Tag (mapN i f p x)
-
-instance MapN phi f => MapN phi (C c f) where
-  mapN i f p (C x) = liftM C (mapN i f p x)
-
--- Todo: is this the best choice?
-instance (CountI phi f, MapN phi f) => MapN phi ([] :.: f) where
-  mapN i f p (D [])     = return $ D []
-  mapN i f p (D (x:xs)) = do h <- mapN i f p x
-                             t <- mapN (i + countI p x) f p (D xs)
-                             return $ D (h : unD t)
-
---------------------------------------------------------------------------------
--- CountI
---------------------------------------------------------------------------------
-
-class CountI phi (f :: (* -> *) -> * -> *) where
-  -- | Count the number of recursive occurrences
-  countI :: phi ix -> f r ix -> Int
-
-instance El phi xi => CountI phi (I xi) where
-  countI _ _ = 1
-
-instance CountI phi (K a) where
-  countI _ _ = 0
-
-instance CountI phi U where
-  countI _ _ = 0
-
-instance (CountI phi f, CountI phi g) => CountI phi (f :+: g) where
-  countI p (L x) = countI p x
-  countI p (R x) = countI p x
-
-instance (CountI phi f, CountI phi g) => CountI phi (f :*: g) where
-  countI p (x :*: y) = countI p x + countI p y
-
-instance CountI phi f => CountI phi (f :>: ix) where
-  countI p (Tag x) = countI p x
-
-instance CountI phi f => CountI phi (C c f) where
-  countI p (C x) = countI p x
-
--- Todo: is this the best choice?
-instance CountI phi f => CountI phi ([] :.: f) where
-  countI p (D x) = sum (map (countI p) x)
-
---------------------------------------------------------------------------------
--- Children
---------------------------------------------------------------------------------
-
--- | Get the immediate children
-imChildren :: (Fam phi, Children phi (PF phi)) => phi ix -> ix -> [Any phi]
-imChildren p x = children (\p (I0 v) -> Any p v) p (from p x)
-
--- | Get all children with their paths
-childrenPaths :: (Fam phi, Children phi (PF phi)) => phi ix -> ix -> [(Any phi, Path)]
-childrenPaths p a = (Any p a, []) : 
-                    [ (r, n : p)
-                    | (n, Any p' c) <- zip [0..] (imChildren p a)
-                    , (r, p) <- childrenPaths p' c ]
-
-class Children phi (f :: (* -> *) -> * -> *) where
-  children :: (forall ix. phi ix -> r ix -> Any phi) -> phi ix -> f r ix -> [Any phi]
-
-instance (Fam phi, El phi xi) => Children phi (I xi) where
-  children mka _ (I r) = [mka proof r]
-
-instance Children phi (K a) where
-  children _ _ (K _) = []
-
-instance Children phi U where
-  children _ _ U = []
-
-instance (Children phi f, Children phi g) => Children phi (f :+: g) where
-  children mka p (L x) = children mka p x
-  children mka p (R x) = children mka p x
-
-instance (Children phi f, Children phi g) => Children phi (f :*: g) where
-  children mka p (x :*: y) = children mka p x ++ children mka p y
-
-instance Children phi f => Children phi (C c f) where
-  children mka p (C x) = children mka p x
-
-instance Children phi f => Children phi (f :>: ix) where
-  children mka p (Tag x) = children mka p x
-
--- Todo: is this the best choice?
-instance Children phi f => Children phi ([] :.: f) where
-  children mka p (D x) = concatMap (children mka p) x
-
---------------------------------------------------------------------------------
--- Nicer interface
---------------------------------------------------------------------------------
-
-class HasRef phi where
-  type RefRep phi ix
-  -- I don't like HFix here but can't figure out how to do a
-  -- single step unwrapping
-  toRef   :: phi ix -> HFix (WithRef phi) ix -> RefRep phi ix
-  fromRef :: phi ix -> RefRep phi ix -> HFix (WithRef phi) ix
-
-data NiceInsert phi where
-  NiceInsert :: phi ix -> Path -> RefRep phi ix -> NiceInsert phi
-
-type NiceTransformation phi = [ NiceInsert phi]
-
-toNiceTransformation :: HasRef phi => Transformation phi -> NiceTransformation phi
-toNiceTransformation = map f
-  where f (AnyInsert p l x) = NiceInsert p l (toRef p x)
-
-fromNiceTransformation :: HasRef phi => NiceTransformation phi -> Transformation phi
-fromNiceTransformation = map f
-  where f (NiceInsert p l x) = AnyInsert p l (fromRef p x)
diff --git a/Generics/MultiRec/Transformations/Main.hs b/Generics/MultiRec/Transformations/Main.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Transformations/Main.hs
@@ -0,0 +1,190 @@
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE PolyKinds                  #-}
+{-# LANGUAGE ConstraintKinds            #-}
+
+module Generics.MultiRec.Transformations.Main
+    ( diff, apply, Ixs, Transformation )
+  where
+
+import Generics.MultiRec hiding ( show, foldM )
+import Control.Applicative ( (<|>) )
+import Control.Monad ( foldM )
+import Control.Monad.State hiding ( foldM, mapM )
+
+import Generics.MultiRec.ShallowEq
+import Generics.MultiRec.Transformations.Path
+import Generics.MultiRec.Transformations.Children
+import Generics.MultiRec.Transformations.ZipChildren
+import Generics.MultiRec.Transformations.MemoTable
+
+--------------------------------------------------------------------------------
+-- Synonyms
+--------------------------------------------------------------------------------
+
+-- | A constraint synonym for convenience
+type Transform phi = ( Fam phi, HFunctor phi (PF phi), SEq phi (PF phi)
+                     , ZipChildren phi (PF phi), MapP phi (PF phi)
+                     , Extract (PF phi))
+
+-- | Transformations are just sequences of insertions
+type Transformation phi top = [ Insert phi top top ]
+
+--------------------------------------------------------------------------------
+-- Applying
+--------------------------------------------------------------------------------
+
+-- | Apply the transformation to the given tree
+apply :: forall phi ix. (Transform phi)
+         => phi ix -> ix -> Transformation phi ix -> Maybe ix
+apply p t = foldM apply' t where
+  apply' :: ix -> Insert phi ix ix -> Maybe ix
+  apply' a (Insert _ loc repl) = mapP p loc (\pt _ -> lookupRefs p t pt repl) a
+
+-- | Look up the references using the original structure
+lookupRefs :: forall phi top a. (Transform phi)
+              => phi top -> top -> phi a -> HWithRef phi top a -> Maybe a
+lookupRefs p r p' (HIn (InR x))   = liftM (to p') $
+                                    hmapM (\p'' -> liftM I0 . lookupRefs p r p'') p' x
+lookupRefs p r _  (HIn (Ref loc)) = extract p loc r
+
+-- | Extract the subtree at the given path
+extract :: forall phi i t. (Transform phi)
+        => phi i -> Path phi t i -> i -> Maybe t
+extract w1 Empty          x = Just x
+extract w1 (Push w2 p ps) x =     fmap unI0 (extract' return w1 p (from w1 x))
+                              >>= extract w2 ps
+
+class Extract f where
+  extract' :: (r t -> Maybe (r t))
+           -> phi ix -> Dir f t ix -> f r ix -> Maybe (r t)
+
+instance (Extract f, Extract g) => Extract (f :+: g) where
+  extract' f w (CL p) (L x) = extract' f w p x
+  extract' f w (CR p) (R x) = extract' f w p x
+  extract' f w _      _     = Nothing
+
+instance (Extract f, Extract g) => Extract (f :*: g) where
+  extract' f w (C1 p _) (x :*: _) = extract' f w p x
+  extract' f w (C2 _ p) (_ :*: y) = extract' f w p y
+
+instance Extract (I ix) where
+  extract' f w CId (I x) = f x
+
+instance Extract U     where extract' _ _ _ _ = Nothing
+instance Extract (K a) where extract' _ _ _ _ = Nothing
+
+instance (Extract f) => Extract (f :>: ix) where
+  extract' f w (CTag p) (Tag x) = extract' f w p x
+
+instance (Extract f) => Extract (C c f) where
+  extract' f w (CC p) (C x) = extract' f w p x
+
+instance (Extract f) => Extract (Maybe :.: f) where
+  extract' f w (CCM p) (D x) = x >>= extract' f w p
+
+instance (Extract f) => Extract ([] :.: f) where
+  extract' f w (CCL l p _) (D x) = extract' f w p (x !! length l)
+
+--------------------------------------------------------------------------------
+-- Diffing
+--------------------------------------------------------------------------------
+-- | Find a set of insertions to transform the first into the second tree
+
+-- Jeroen says: we could make the code of uses nicer if we define a
+-- <|>' :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a)
+-- then it will look similar to the version in the paper
+diff :: forall phi top. (Transform phi, Children phi (PF phi) top, EmptyMemo phi top (Ixs phi), ChildrenTable phi top (Ixs phi), GetChildrenTable phi (Ixs phi) top, Eq top)
+        => phi top -> top -> top -> Transformation phi top
+diff p a b = runMemo (Proxy :: Proxy '(phi,top)) $ build False p a b where
+  chTbl :: HList (ChildTable phi top (Ixs phi))
+  chTbl = childrenTable (Proxy :: Proxy '(phi, top,Ixs phi)) a
+  build :: forall a. (Children phi (PF phi) a, Eq a, GetChildrenTable phi (Ixs phi) a) => Bool -> phi a -> a -> a -> Memo phi top [ Insert phi top a ]
+  build False p' a' b' | a' == b' = return []
+  build ins   p' a' b' =
+    let -- All children of this type
+        allChildren :: Children phi (PF phi) a => [(Path phi a top, a)]
+        allChildren = getChTable (Proxy :: Proxy '(phi, top, Ixs phi)) chTbl
+    in case childLookup p' b' allChildren of
+      Just l  -> return [ Insert p' Empty (HIn (Ref l)) ]
+      Nothing -> uses >>= maybe insert return where -- Only insert when we cannot reuse
+        -- Construct the edits for the children based on a root
+        construct :: Bool -> a -> Memo phi top (Maybe [ Insert phi top a ])
+        construct ins' c =
+          if shallowEq p' (from p' c) (from p' b')
+          then do r <- zipChildrenM p'
+                       (\p1 l1 c1 c2 -> recMemo build ins' p1 c1 c2
+                                        >>= return . map (updatePath l1)
+                       ) c b'
+                  return $ Just $ concat r
+          else return Nothing
+        -- Possible edits reusing the existing tree or using a part of
+        -- the original tree. The existing tree is only used if we didn't
+        -- just insert it, since we want to keep the inserts small
+        uses :: Memo phi top (Maybe [ Insert phi top a ])
+        uses =  reuses >>= \re -> case re of
+          Just r | ins -> return re
+          _            -> construct ins a' >>= return . pickBest re
+        -- Possible edits that include reusing a part of the original tree
+        reuses :: Memo phi top (Maybe [ Insert phi top a ])
+        reuses = foldM f Nothing allChildren where
+          f :: Maybe [ Insert phi top a ] -> (Path phi a top, a)
+               -> Memo phi top (Maybe [ Insert phi top a ])
+          f c (l,x) = construct False x >>= return . pickBest c . addRef l
+          addRef :: Path phi a top -> Maybe [ Insert phi top a ]
+                    -> Maybe [ Insert phi top a ]
+          addRef l = liftM ((Insert p' Empty (HIn (Ref l))):)
+        -- Best edit including insertion, only chosen if nothing can be reused
+        insert :: Memo phi top [ Insert phi top a ]
+        insert = do
+          Just r <- construct True b'
+          let (r',e') = partialApply p' (annotate p' b') r
+          return $ (Insert p' Empty r') : e'
+
+-- | Update insert location
+updatePath :: Path phi a b -> Insert phi top a -> Insert phi top b
+updatePath p (Insert w loc v) = Insert w (p <.> loc) v
+
+-- | Pick the best edit
+pickBest :: Maybe [a] -> Maybe [a] -> Maybe [a]
+pickBest e1 e2 = case (e1,e2) of
+  (Just e1', Just e2') -> Just (pickShortest e1' e2')
+  _                    -> e1 <|> e2
+
+-- | Pick the shortest of two lists lazily
+pickShortest :: [a] -> [a] -> [a]
+pickShortest a b = if f a b then a else b
+  where f []     _      = True
+        f _      []     = False
+        f (_:xs) (_:ys) = f xs ys
+
+-- | Lookup a child with a given type
+childLookup :: (Fam phi, Eq t)
+             => phi t -> t -> [(Path phi t ix, t)] -> Maybe (Path phi t ix)
+childLookup p _ [] = Nothing
+childLookup p x ((r,y) : ys) | x == y    = Just r
+                             | otherwise = childLookup p x ys
+
+-- | Lift a tree to an edit structure
+annotate :: (Fam phi, HFunctor phi (PF phi))
+         => phi ix -> ix -> HWithRef phi top ix
+annotate p = HIn . InR . hmap (\p' (I0 x) -> annotate p' x) p . from p
+
+-- | Try to apply as much edits to the edit structure as possible
+--   to make the final edit smaller
+partialApply :: forall phi top a. (Transform phi)
+                => phi a
+                -> HWithRef phi top a
+                -> [Insert phi top a]
+                -> (HWithRef phi top a, [Insert phi top a])
+partialApply _ a [] = (a, [])
+partialApply p a (Insert w l x : xs) = case mapPR p l (\_ _ -> Just x) a of
+  Just a' -> partialApply p a' xs
+  Nothing -> let (a',xs') = partialApply p a xs in (a', Insert w l x : xs')
diff --git a/Generics/MultiRec/Transformations/MemoTable.hs b/Generics/MultiRec/Transformations/MemoTable.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Transformations/MemoTable.hs
@@ -0,0 +1,165 @@
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE OverlappingInstances       #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE DataKinds                  #-}
+{-# LANGUAGE PolyKinds                  #-}
+
+module Generics.MultiRec.Transformations.MemoTable where
+
+import Generics.MultiRec hiding ( show, foldM )
+import Control.Monad.State hiding ( foldM, mapM )
+import qualified Data.Map as Map
+import Data.Map ( Map )
+
+import Generics.MultiRec.Transformations.Path
+import Generics.MultiRec.Transformations.Children
+
+--------------------------------------------------------------------------------
+-- One memotable per type in the family
+--------------------------------------------------------------------------------
+type family Ixs (phi :: * -> *) :: [*] -- one instance per family; tells us
+                                       -- which types are in the family
+
+data HList (l :: [*]) where -- heterogeneous collections
+  HNil  :: HList '[]
+  HCons :: h -> HList t -> HList (h ': t)
+
+type family HMap (h :: * -> * -> *) (f :: * -> *) (g :: * -> *) (l :: [*]) :: [*]
+type instance HMap h f g '[]      = '[]
+type instance HMap h f g (t ': ts) = h (f t) (g t) ': HMap h f g ts
+
+-- Memotables are now heterogenous collections mapping keys to values, indexed
+-- over each family type
+-- type MemoTable' phi top ixs = HList (HMap Map (MemKey' top) (MemVal' top) ixs)
+type MemoTable phi top ixs = HList (MemoTable' One phi top ixs)
+
+data Type = One | Two
+
+type family MemoTable' (x :: Type) (phi :: * -> *) top (ixs :: [*]) :: [*]
+type instance MemoTable' x phi top '[]       = '[]
+type instance MemoTable' x phi top (t ': ts) = MemCell x phi top t
+                                            ': MemoTable' x phi top ts
+
+type family MemCell (x :: Type) (phi :: * -> *) top (t :: *) :: *
+-- type instance MemCell One phi top t = Map (MemKey t) (MemVal phi top  t)
+type instance MemCell One phi top t = Map (MemKey t) (MemVal phi top  t)
+
+type MemKey         t = (Bool, t, t)
+type MemVal phi top t = [Insert phi top t]
+
+-- Lookup on the right table
+data Proxy (t :: k) = Proxy
+class {- (ixs ~ Ixs phi) => -} Lookup phi (ixs :: [*]) ix where
+  lookupMT :: Proxy '(phi, ixs)
+           -- I don't like this Proxy too much, but I'm afraid it's necessary
+           -> MemoTable phi top ixs -> MemKey ix -> Maybe (MemVal phi top ix)
+  insertMT :: Proxy '(phi, ixs)
+              -> MemKey ix -> MemVal phi top ix
+              -> MemoTable phi top ixs -> MemoTable phi top ixs
+
+-- this probably shouldn't happen...
+instance Lookup phi '[] ix where
+  lookupMT _ HNil _ = Nothing
+  insertMT _ _ _ HNil = HNil
+
+-- this is the right memotable for this type
+instance (Ord t) => Lookup phi (t ': ts) t where
+  lookupMT _ (HCons mt _) k = Map.lookup k mt
+  insertMT _ k v (HCons mt tl) = HCons (Map.insert k v mt) tl
+
+-- this is not the right memotable for this type, keep searching
+instance (Lookup phi ts ix) => Lookup phi (t ': ts) ix where
+  lookupMT _ (HCons _ mts) = lookupMT (Proxy :: Proxy '(phi, ts)) mts
+  insertMT _ k v (HCons hd mts) = HCons hd (insertMT (Proxy :: Proxy '(phi, ts)) k v mts)
+
+type Memo phi top a = State (MemoTable phi top (Ixs phi)) a
+
+class EmptyMemo (phi :: * -> *) top (ixs :: [*]) where
+  emptyMemo :: Proxy '(phi,top,ixs) -> MemoTable phi top ixs
+
+instance EmptyMemo phi top '[] where
+  emptyMemo _ = HNil
+
+instance (EmptyMemo phi top t) => EmptyMemo phi top (h ': t) where
+  emptyMemo _ = HCons Map.empty (emptyMemo (Proxy :: Proxy '(phi,top,t)))
+
+runMemo :: forall phi top a. (EmptyMemo phi top (Ixs phi))
+        => Proxy '(phi,top) -> Memo phi top a -> a
+runMemo _ = flip evalState (emptyMemo (Proxy :: Proxy '(phi,top,Ixs phi)))
+
+recMemo :: forall phi top ix.
+           (Fam phi, Children phi (PF phi) ix, Lookup phi (Ixs phi) ix, Eq ix, GetChildrenTable phi (Ixs phi) ix) =>
+           (forall ix. (Children phi (PF phi) ix, Lookup phi (Ixs phi) ix, Eq ix, GetChildrenTable phi (Ixs phi) ix) => Bool -> phi ix -> ix -> ix -> Memo phi top [ Insert phi top ix ])
+           -> Bool -> phi ix -> ix -> ix -> Memo phi top [ Insert phi top ix ]
+recMemo f a p b c = do
+  mp <- get
+  let k = (a,b,c)
+  case lookupMT (Proxy :: Proxy '(phi, Ixs phi)) mp k of
+    Just r -> return r
+    Nothing -> do
+      r <- f a p b c
+      modify $ insertMT (Proxy :: Proxy '(phi, Ixs phi)) k r
+      return r
+
+--------------------------------------------------------------------------------
+-- Memo table of all children
+--------------------------------------------------------------------------------
+-- type family ChildTable (phi :: * -> *) top (ixs :: [*]) :: [*]
+-- type instance ChildTable phi top '[]       = '[]
+-- type instance ChildTable phi top (t ': ts) = [(Path phi top t, t)] ': ChildTable phi top ts
+
+type ChildTable phi top ixs = MemoTable' Two phi top ixs
+type instance MemCell Two phi top t = [(Path phi t top, t)]
+
+{-
+This is a first step to merge ChildTable and MemoTable. However, it would be
+really cool if we can also merge getChTable and lookupMT, for example. But for
+that we have to change MemCell to either be a Map or a list of pairs.
+
+Changing ChildTable to use a Map as its cell isn't nice, because we start
+requiring |Ord (r ix)| constraints in AllChildren.
+
+The other way around, changing MemoTable to use a list of pairs instead, is
+probably possible, but I'm not sure if it's a good idea. I'd like Jeroen's
+opinion on this.
+-}
+
+class ChildrenTable (phi :: * -> *) top (ixs :: [*]) where
+  childrenTable :: Proxy '(phi,top,ixs) -> top -> HList (ChildTable phi top ixs)
+
+instance ChildrenTable phi top '[] where
+  childrenTable _ _ = HNil
+
+-- For the toplevel type, also include full tree
+instance (Fam phi, El phi top, Children phi (PF phi) top, ChildrenTable phi top t)
+         => ChildrenTable phi top (top ': t) where
+  childrenTable _ top = HCons ((Empty,top) : allChildren proof proof top)
+                        (childrenTable (Proxy :: Proxy '(phi,top,t)) top)
+
+-- For all other types
+instance (Fam phi, El phi h, El phi top, Children phi (PF phi) h, ChildrenTable phi top t)
+         => ChildrenTable phi top (h ': t) where
+  childrenTable _ top = HCons (allChildren proof proof top)
+                        (childrenTable (Proxy :: Proxy '(phi,top,t)) top)
+
+class GetChildrenTable phi (ixs :: [*]) ix where
+  getChTable :: Proxy '(phi, top, ixs)
+           -- I don't like this Proxy too much, but I'm afraid it's necessary
+           -> HList (ChildTable phi top ixs) -> MemCell Two phi top ix
+
+instance GetChildrenTable phi '[] ix where
+  getChTable _ HNil = error "This shouldn't happen"
+
+instance (Ord t) => GetChildrenTable phi (t ': ts) t where
+  getChTable _ (HCons mt _) = mt
+
+-- this is not the right memotable for this type, keep searching
+instance (GetChildrenTable phi ts ix) => GetChildrenTable phi (t ': ts) ix where
+  getChTable _ (HCons _ mts) = getChTable (Proxy :: Proxy '(phi, top, ts)) mts
diff --git a/Generics/MultiRec/Transformations/Path.hs b/Generics/MultiRec/Transformations/Path.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Transformations/Path.hs
@@ -0,0 +1,250 @@
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+module Generics.MultiRec.Transformations.Path (
+    module Generics.MultiRec.Transformations.Path
+  , Ctxs(..), Ctx(..)
+  ) where
+
+import Prelude as P hiding ( mapM, sequence )
+import Generics.MultiRec hiding ( show, foldM )
+import Generics.MultiRec.Zipper ( Ctxs(..), Ctx(..) )
+import Control.Monad.State hiding ( foldM, mapM, sequence )
+import Data.Traversable ( Traversable, mapM, sequence )
+
+import Generics.MultiRec.CountIs
+
+--------------------------------------------------------------------------------
+-- Paths, annotations and edits
+--------------------------------------------------------------------------------
+-- | A path is a list of connecting directions on a datatype. This is equivalent
+-- to a zipper context where the recursive positions are ignored (set to a
+-- constant type).
+type Path  phi t i = Ctxs phi t (K0 ()) i
+
+-- | A direction points to a single recursive position in a datatype.
+type Dir f t i = Ctx f t (K0 ()) i
+
+-- | The type of pattern functors extended with references
+data WithRef phi top r a = InR { unInR :: PF phi r a }
+                         | Ref { unRef :: Path phi a top }
+
+-- | Closed functors extended with references
+type HWithRef phi top t = HFix (WithRef phi top) t
+
+-- | Insertions contain a path of where to insert, and what to insert
+data Insert phi top ix where
+  Insert :: phi t -> Path phi t ix -> HWithRef phi top t -> Insert phi top ix
+
+--------------------------------------------------------------------------------
+-- Path helpers
+--------------------------------------------------------------------------------
+
+-- | Concatenate two paths
+(<.>) :: forall phi a b c. Path phi b a -> Path phi c b -> Path phi c a
+Empty         <.> p2 = p2
+(Push p x xs) <.> p2 = Push p x (xs <.> p2)
+--------------------------------------------------------------------------------
+-- Show instances
+--------------------------------------------------------------------------------
+
+newtype ConIndex = CI Int deriving (Eq, Num)
+
+instance Show ConIndex where
+  show (CI (-1)) = ""
+  show (CI n   ) = "_" ++ show n ++ " "
+
+class ShowPath f where
+  showsPrecPath :: ShowS -> ConIndex -> Int -> Dir f i t -> ShowS
+
+instance (ShowPath f, ShowPath g) => ShowPath (f :+: g) where
+  showsPrecPath r d n (CL p) = showsPrecPath r d n p
+  showsPrecPath r d n (CR p) = showsPrecPath r d n p
+
+instance (ShowPath f, ShowPath g, CountIs f) => ShowPath (f :*: g) where
+  -- Going left on a product is unproblematic
+  showsPrecPath r d n (C1 p _) = showsPrecPath r d n p
+  -- Going right, however, we have to increase |d| by the number of children to
+  -- our left, unless |d == -1|, which means we are under a composition, and
+  -- shouldn't print any indices anymore.
+  showsPrecPath r d n (C2 _ p) =
+    let newd = if d == -1 then -1 else d + CI (countIs (undefined :: f r ix))
+    in showsPrecPath r newd n p
+
+instance (ShowPath f) => ShowPath (f :>: ix) where
+  showsPrecPath r d n (CTag p) = showsPrecPath r d n p
+
+instance (ShowPath f, Constructor c) => ShowPath (C c f) where
+  showsPrecPath r d n (CC p) = let name = conName (undefined :: C c f r ix)
+                               in showParen (n > 10) $ showString name
+                                                     . showsPrecPath r 0 11 p
+
+instance ShowPath (K a) where showsPrecPath _ _ _ _ = id
+instance ShowPath U     where showsPrecPath _ _ _ _ = id
+
+instance ShowPath (I ix) where
+  showsPrecPath r d n CId = shows d . r
+
+instance (ShowPath f) => ShowPath (Maybe :.: f) where
+  showsPrecPath r d n (CCM p) = shows d
+                              . showParen (n > 10)
+                                  ( showString "Maybe_0 "
+                                  . showsPrecPath r (-1) 11 p)
+
+instance (ShowPath f) => ShowPath ([] :.: f) where
+  showsPrecPath r d n (CCL l1 p l2) = shows d
+                                    . showParen (n > 10)
+                                        ( showString "List_"
+                                        . P.showsPrec 11 (length l1)
+                                        . showChar ' '
+                                        . showsPrecPath r (-1) 11 p)
+
+showsPrecPathC :: (ShowPath (PF phi))
+               => ConIndex -> Int -> Path phi t i -> ShowS
+showsPrecPathC d n Empty         = showString "End"
+showsPrecPathC d n (Push w p ps) = showsPrecPath (showsPrecPathC d n ps) d n p
+
+instance (ShowPath (PF phi)) => Show (Path phi t i) where
+  showsPrec = showsPrecPathC 0
+
+instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix, ShowPath (PF phi))
+         => Show (HWithRef phi top ix) where
+  showsPrec = showWR proof
+
+instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix, ShowPath (PF phi))
+         => Show (Insert phi top ix) where
+  showsPrec n (Insert w p r) = showParen (n > 10) $
+    showString "Insert " . spaces [P.showsPrec 11 p, showWR w 11 r]
+
+-- showsPrec for WithRef working with type index
+showWR :: forall phi top ix.
+          (HFunctor phi (PF phi), HShow phi (PF phi), ShowPath (PF phi))
+       => phi ix -> Int -> HWithRef phi top ix -> ShowS
+showWR w n (HIn (InR p)) = showParen (n > 10) $ spaces (("InR"++) : map ($ 11) x) where
+    f :: forall ix. phi ix -> HWithRef phi top ix -> K0 [Int -> ShowS] ix
+    f w wr = K0 [\n -> showWR w n wr]
+    r :: PF phi (K0 [Int -> ShowS]) ix
+    r = hmap f w p
+    x :: [Int -> ShowS]
+    x = hShowsPrecAlg w r
+showWR w n (HIn (Ref p)) = showParen (n > 10) $ showString "Ref " . P.showsPrec 11 p
+
+{-
+showsPrecPath :: forall phi f i t. ConIndex -> Int -> Dir phi f i t -> ShowS
+showsPrecPath d _ End        = showString "End"
+showsPrecPath d n (PlusL p)  = showsPrecPath d     n p
+showsPrecPath d n (PlusR p)  = showsPrecPath d     n p
+
+-- Going left on a product is unproblematic
+showsPrecPath d n (ProdL p)  = showsPrecPath d     n p
+
+-- Going right, however, we have to increase |d| by the number of children to
+-- our left, unless |d == -1|, which means we are under a composition, and
+-- shouldn't print any indices anymore.
+showsPrecPath d n (ProdR (p :: Dir phi g i t))  =
+  let newd = if d == -1 then -1 else d + CI (countIs (undefined :: g r ix))
+  in showsPrecPath newd n p
+
+showsPrecPath d n (TagP  p)  = showsPrecPath d     n p
+showsPrecPath d n (ConsP p)  = let name = conName (undefined :: f r i)
+                               in showParen (n > 10) $ showString name
+                                                     . showsPrecPath 0 11 p
+showsPrecPath d n (RecP _ p) = shows d . showsPrecPath d n p
+showsPrecPath d n (TrvI i p) = shows d
+                             . showParen (n > 10) (spaces
+                                 [ showString "TrvI"
+                                 , P.showsPrec 11 i
+                                 , showsPrecPath (-1) 11 p])
+
+instance Show (Dir phi f i t) where
+  showsPrec = showsPrecPath 0
+
+instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix)
+         => Show (WithRef phi top ix) where
+  showsPrec = showWR proof
+
+instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix)
+         => Show (Insert phi top ix) where
+  showsPrec n (Insert w p r) = showParen (n > 10) $
+    showString "Insert " . spaces [P.showsPrec 11 p, showWR w 11 r]
+
+-- showsPrec for WithRef working with type index
+showWR :: forall phi top ix. (HFunctor phi (PF phi), HShow phi (PF phi))
+       => phi ix -> Int -> WithRef phi top ix -> ShowS
+showWR w n (InR p) = showParen (n > 10) $ spaces (("InR"++) : map ($ 11) x) where
+    f :: forall ix. phi ix -> WithRef phi top ix -> K0 [Int -> ShowS] ix
+    f w wr = K0 [\n -> showWR w n wr]
+    r :: PF phi (K0 [Int -> ShowS]) ix
+    r = hmap f w p
+    x :: [Int -> ShowS]
+    x = hShowsPrecAlg w r
+showWR w n (Ref p) = showParen (n > 10) $ showString "Ref " . P.showsPrec 11 p
+-}
+
+--------------------------------------------------------------------------------
+-- MapP
+--------------------------------------------------------------------------------
+mapP :: forall m phi i t. (Monad m, Fam phi, MapP phi (PF phi))
+     => phi i -> Path phi t i -> (phi t -> t -> m t) -> i -> m i
+mapP w1 Empty         f = f w1
+mapP w1 (Push w2 y p) f =
+  liftM (to w1) . mapP' (\w -> liftM I0 . mapP w p f . unI0) w1 y . from w1
+
+class MapP phi f where
+  mapP' :: Monad m
+        => (phi t -> r t -> m (r t))
+        -> phi ix -> Dir f t ix -> f r ix -> m (f r ix)
+
+instance MapP phi U     where mapP' f phi p = return
+instance MapP phi (K a) where mapP' f phi p = return
+
+instance (El phi ix) => MapP phi (I ix) where
+  mapP' f phi CId (I x) = liftM I (f proof x)
+
+instance (MapP phi f, MapP phi g) => MapP phi (f :+: g) where
+  mapP' f phi (CL p) (L x) = liftM L (mapP' f phi p x)
+  mapP' f phi (CR p) (R x) = liftM R (mapP' f phi p x)
+  mapP' _ _   _      _     = fail "mapP': inconsistent sum"
+
+instance (MapP phi f, MapP phi g) => MapP phi (f :*: g) where
+  mapP' f phi (C1 p _) (x :*: y) = liftM2 (:*:) (mapP' f phi p x) (return y)
+  mapP' f phi (C2 _ p) (x :*: y) = liftM2 (:*:) (return x) (mapP' f phi p y)
+
+instance (MapP phi f) => MapP phi (C c f) where
+  mapP' f phi (CC p) (C x) = liftM C (mapP' f phi p x)
+
+instance (MapP phi f) => MapP phi (f :>: ix) where
+  mapP' f phi (CTag p) (Tag x) = liftM Tag (mapP' f phi p x)
+
+instance (MapP phi f) => MapP phi (Maybe :.: f) where
+  mapP' f phi (CCM p) = liftM D . sequence . liftM (mapP' f phi p) . unD
+
+instance (MapP phi f) => MapP phi ([] :.: f) where
+  mapP' f phi (CCL x p _) = liftM D . mapMwithI (\i ->
+                                                  if i == length x
+                                                  then mapP' f phi p
+                                                  else return) . unD
+
+
+mapPR :: forall phi top t a. (Fam phi, MapP phi (PF phi))
+         => phi a -> Path phi t a
+         -> (phi t -> HWithRef phi top t -> Maybe (HWithRef phi top t))
+         -> HWithRef phi top a -> Maybe (HWithRef phi top a)
+mapPR _  _             _  (HIn (Ref _)) = Nothing
+mapPR w1 Empty         f       a        = f w1 a
+mapPR w1 (Push w2 y p) f  (HIn (InR a)) =
+  liftM (HIn . InR) . mapP' (\w -> mapPR w p f) w1 y $ a
+
+mapMwithI :: (Monad m, Traversable t) => (Int -> a -> m b) -> t a -> m (t b)
+mapMwithI f ta = evalStateT (mapM g ta) 0 where
+  g a = do i <- get
+           put $ i+1
+           lift $ f i a
diff --git a/Generics/MultiRec/Transformations/RewriteRules.hs b/Generics/MultiRec/Transformations/RewriteRules.hs
deleted file mode 100644
--- a/Generics/MultiRec/Transformations/RewriteRules.hs
+++ /dev/null
@@ -1,59 +0,0 @@
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE TemplateHaskell            #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE EmptyDataDecls             #-}
-{-# LANGUAGE RankNTypes                 #-}
-{-# LANGUAGE GADTs                      #-}
-
-module Generics.MultiRec.Transformations.RewriteRules (
-  Transformation, Transform, apply, insert, AnyInsert (..)
-  ) where
-
-import Generics.MultiRec hiding ( foldM )
-import Generics.MultiRec.Rewriting
-import Generics.MultiRec.Zipper (Zipper, Loc, leave, enter, update)
-
-import Data.Maybe ( fromJust )
-import Control.Monad ( (>=>), foldM )
-
---------------------------------------------------------------------------------
--- Patch
---------------------------------------------------------------------------------
--- Basically, a class synonym
-class (Zipper phi (PF phi), Rewrite phi) => Transform phi
-instance Transform phi => Rewrite phi
-
--- An edit is a list of:
-type Transformation phi a = [ AnyInsert phi a ]
-
--- Existential for insertion
-data AnyInsert phi a where 
-  AnyInsert ::
-    -- Proof
-    phi ix
-    -- A path to the location to edit
-    -> (Loc phi I0 a -> Maybe (Loc phi I0 a)) 
-    -- The rewrite rule to apply there
-    -> Rule phi ix
-    -> AnyInsert phi a
-
-insert :: El phi ix => (Loc phi I0 a -> Maybe (Loc phi I0 a)) -> Rule phi ix
-          -> AnyInsert phi a
-insert = AnyInsert proof
-
--- Patching is terribly simple: at the given locations, apply all the rules,
--- then exit the zipper.
-apply :: Transform phi => Transformation phi a -> phi a -> a -> Maybe a
-apply rs p x = fmap leave $ foldM appRule (enter p x) rs
-  where appRule a (AnyInsert p' l r) = l a >>=
-                            updateM (\p'' -> case eqS p' p'' of
-                                              Nothing   -> const Nothing
-                                              Just Refl -> rewriteM r)
-
-updateM :: (forall xi. phi xi -> xi -> Maybe xi)
-        -> Loc phi I0 ix -> Maybe (Loc phi I0 ix)
--- updateM f (Loc p (I0 x) s) = f p x >>= \y -> Loc p (I0 y) s
-updateM f = Just . update (\p -> maybe (error "updateM") id . f p)
diff --git a/Generics/MultiRec/Transformations/TH.hs b/Generics/MultiRec/Transformations/TH.hs
deleted file mode 100644
--- a/Generics/MultiRec/Transformations/TH.hs
+++ /dev/null
@@ -1,241 +0,0 @@
-{-# LANGUAGE TemplateHaskell            #-}
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE GADTs                      #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE PatternGuards              #-}
-
-module Generics.MultiRec.Transformations.TH ( 
-  deriveRefRep, prefix, postfix
-  ) where
-
-import Generics.MultiRec hiding (show)
-import Generics.MultiRec.TH
-import Language.Haskell.TH hiding (Stmt ())
-import Generics.MultiRec.Transformations.Explicit
-import Control.Monad
-import Control.Applicative
-import Debug.Trace
-
--- | Derive data type with references and 'HasRef' instance. For a data type
---   N the name of the constructor for a reference is RefN, and the given
---   function is used to change the rest of the constructors and the data
---   type name itself. For example, for the following definition:
---
--- > data Tree = Leaf Int | Bin Tree Tree
--- > data TreeAST :: * -> * where
--- >    Tree :: TreeAST Tree
--- > $(deriveRefRep ''TreeAST (postfix "R"))
---
--- The following data type is generated:
---
--- > data TreeR = LeafR Int | BinR TreeR TreeR | RefTree Path
--- > instance HasRef TreeAST
-deriveRefRep :: Name -> (Name -> Name) -> Q [Dec]
-deriveRefRep n namef =
-  do
-    info <- reify n
-    let ps  = init (extractParameters info)
-    let nps = map (\ (n, ps) -> (remakeName n, ps)) (extractConstructorNames ps info)
-    let ns  = map fst nps
-    d <- deriveDatas n namef ps ns
-    r <- deriveHasRef n namef ps ns
-    return $ d ++ r
-
-prefix :: String -> Name -> Name
-prefix pref n = mkName $ pref ++ nameBase n
-
-postfix :: String -> Name -> Name
-postfix post n = mkName $ nameBase n ++ post
-
--- | Turn a record-constructor into a normal constructor by just
--- removing all the field names.
-stripRecordNames :: Con -> Con
-stripRecordNames (RecC n f) =
-  NormalC n (map (\(_, s, t) -> (s, t)) f)
-stripRecordNames c = c
-
-unApp :: Type -> [Type]
-unApp (AppT f a) = unApp f ++ [a]
-unApp t          = [t]
-
--- | Process the reified info of the index GADT, and extract
--- its constructor names, which are also the names of the datatypes
--- that are part of the family.
-extractConstructorNames :: [Name] -> Info -> [(Name, [Name])]
-extractConstructorNames ps (TyConI (DataD _ _ _ cs _)) = concatMap extractFrom cs
-  where
-    extractFrom :: Con -> [(Name, [Name])]
-    extractFrom (ForallC _ eqs c) = map (\ (n, _) -> (n, concatMap extractEq eqs)) (extractFrom c)
-    extractFrom (InfixC _ n _)    = [(n, [])]
-    extractFrom (RecC n _)        = [(n, [])]
-    extractFrom (NormalC n [])    = [(n, [])]
-    extractFrom _                 = []
-
-    extractEq :: Pred -> [Name]
-    extractEq (EqualP t1 t2) = filter (\ p -> p `elem` ps) (extractArgs t1 ++ extractArgs t2)
-    extractEq _              = []
-
-    extractArgs :: Type -> [Name]
-    extractArgs (AppT x (VarT n)) = extractArgs x ++ [n]
-    extractArgs (VarT n)          = [n]
-    extractArgs _                 = []
-extractConstructorNames _  _                           = []
-
--- | Process the reified info of the index GADT, and extract
--- its type parameters.
-extractParameters :: Info -> [Name]
-extractParameters (TyConI (DataD _ _ ns _ _)) = concatMap extractFromBndr ns
-extractParameters (TyConI (TySynD _ ns _))    = concatMap extractFromBndr ns
-extractParameters _                           = []
-
-extractFromBndr :: TyVarBndr -> [Name]
-extractFromBndr (PlainTV n)    = [n]
-extractFromBndr (KindedTV n _) = [n]
-
-deriveDatas :: Name -> (Name -> Name) -> [Name] -> [Name] -> Q [Dec]
-deriveDatas s namef ps ns = zipWithM (deriveData s namef ps ns) [0..] ns
-
-deriveData :: Name -> (Name -> Name) -> [Name] -> [Name] -> Int -> Name -> Q Dec
-deriveData s namef ps ns i n = do
-  let nm = namef n
-  i <- reify n
-  cons <- case i of
-    TyConI (DataD _ _ _ cs _) -> mapM (mkCon n namef ns) cs
-  r <- normalC (prefix "Ref" n) [return (NotStrict, ConT ''Path)]
-  dataD (cxt []) nm (typeVariables i) (map return $ r : cons) []
-
-mkCon :: Name -> (Name -> Name) -> [Name] -> Con -> Q Con
-mkCon t namef ns (NormalC a b) = normalC (namef a) (map f b) where
-  f :: (Strict, Type) -> Q (Strict, Type)
-  f (s,t) = g t >>= return . (,) s
-  g :: Type -> Q Type
-  g (ConT n) | remakeName n `elem` ns = return (ConT $ namef n)
-  g (AppT f a) = g a >>= return . AppT f
-  g x          = return x
-
-typeVariables :: Info -> [TyVarBndr]
-typeVariables (TyConI (DataD    _ _ tv _ _)) = tv
-typeVariables (TyConI (NewtypeD _ _ tv _ _)) = tv
-typeVariables _                           = []
-
-deriveHasRef :: Name -> (Name -> Name) -> [Name] -> [Name] -> Q [Dec]
-deriveHasRef s namef ps ns =
-  do
-    let tyInsts = [tySynInstD ''RefRep [conT s, conT n] (conT $ namef n) | n <- ns]
-    fcs <- liftM concat $ zipWithM (mkFrom ns namef (length ns)) [0..] ns
-    tcs <- liftM concat $ zipWithM (mkTo   ns namef (length ns)) [0..] ns
-    return <$>
-      instanceD (cxt []) (conT ''HasRef `appT` (foldl appT (conT s) (map varT ps)))
-        (tyInsts ++ [funD 'toRef tcs, funD 'fromRef fcs])
-
-mkFrom :: [Name] -> (Name -> Name) -> Int -> Int -> Name -> Q [Q Clause]
-mkFrom ns namef m i n = do
-  let wrapE e = conE 'HIn `appE` (conE 'InR `appE` lrE m i (conE 'Tag `appE` e))
-  i <- reify n
-  let dn = remakeName n
-  let r = clause [conP dn [], conP (prefix "Ref" dn) [varP (field 0)]]
-               (normalB $ conE 'HIn `appE` (conE 'Ref `appE` varE (field 0))) []
-  let b = case i of
-            TyConI (DataD _ _ _ cs _) ->
-               zipWith (fromCon wrapE ns dn namef (length cs)) [0..] cs
-            TyConI (TySynD t _ _) ->
-              [clause [conP dn [], varP (field 0)] (normalB (wrapE $ conE 'K `appE` varE (field 0))) []]
-            _ -> error "unknown construct"
-  return (r : b)
-
-mkTo :: [Name] -> (Name -> Name) -> Int -> Int -> Name -> Q [Q Clause]
-mkTo ns namef m i n = do
-  let wrapP p = conP 'HIn [conP 'InR [lrP m i (conP 'Tag [p])]]
-  i <- reify n
-  let dn = remakeName n
-  let r = clause [conP dn [], conP 'HIn [conP 'Ref [varP (field 0)]]] 
-               (normalB $ conE (prefix "Ref" dn) `appE` varE (field 0)) []
-  let b = case i of
-             TyConI (DataD _ _ _ cs _) ->
-                  zipWith (toCon wrapP ns dn namef (length cs)) [0..] cs
-             TyConI (TySynD t _ _) ->
-                  [clause [conP dn [], wrapP $ conP 'K [varP (field 0)]] (normalB $ varE (field 0)) []]
-             _ -> error "unknown construct"
-  return (r : b)
-
-
-fromCon :: (Q Exp -> Q Exp) -> [Name] -> Name -> (Name -> Name) -> Int -> Int -> Con -> Q Clause
-fromCon wrap ns n namef m i (NormalC cn []) =
-    clause
-      [conP n [], conP (namef cn) []]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []
-fromCon wrap ns n namef m i (NormalC cn fs) =
-    -- runIO (putStrLn ("constructor " ++ show ix)) >>
-    clause
-      [conP n [], conP (namef cn) (map (varP . field) [0..length fs - 1])]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField ns) [0..] (map snd fs))) []
-  where
-    prod x y = conE '(:*:) `appE` x `appE` y
-fromCon wrap ns n namef m i r@(RecC _ _) =
-  fromCon wrap ns n namef m i (stripRecordNames r)
-fromCon wrap ns n namef m i (InfixC t1 cn t2) =
-  fromCon wrap ns n namef m i (NormalC cn [t1,t2])
-fromCon wrap ns n namef m i (ForallC _ _ c) =
-  fromCon wrap ns n namef m i c
-
-toCon :: (Q Pat -> Q Pat) -> [Name] -> Name -> (Name -> Name) -> Int -> Int -> Con -> Q Clause
-toCon wrap ns n namef m i (NormalC cn []) =
-    clause
-      [conP n [], wrap $ lrP m i $ conP 'C [conP 'U []]]
-      (normalB $ conE $ namef cn) []
-toCon wrap ns n namef m i (NormalC cn fs) =
-    -- runIO (putStrLn ("constructor " ++ show ix)) >>
-    clause
-      [conP n [], wrap $ lrP m i $ conP 'C [foldr1 prod (map (varP . field) [0..length fs - 1])]]
-      (normalB $ foldl appE (conE $ namef cn) (zipWith (toField ns) [0..] (map snd fs))) []
-  where
-    prod x y = conP '(:*:) [x,y]
-toCon wrap ns n namef m i r@(RecC _ _) =
-  toCon wrap ns n namef m i (stripRecordNames r)
-toCon wrap ns n namef m i (InfixC t1 cn t2) =
-  toCon wrap ns n namef m i (NormalC cn [t1,t2])
-toCon wrap ns n namef m i (ForallC _ _ c) =
-  toCon wrap ns n namef m i c
-
-fromField :: [Name] -> Int -> Type -> Q Exp
-fromField ns nr t = [| $(fromFieldFun ns t) $(varE (field nr)) |]
-
-fromFieldFun :: [Name] -> Type -> Q Exp
-fromFieldFun ns t@(ConT n)
-  | remakeName n `elem` ns   = [| I . fromRef $(conE $ remakeName n) |]
-fromFieldFun ns t
-  | ConT n : a <- unApp t, remakeName n `elem` ns
-                             = [| I . fromRef $(conE $ remakeName n) |]
-fromFieldFun ns t@(AppT f a) = [| D . fmap $(fromFieldFun ns a) |]
-fromFieldFun ns t            = [| K |]
-
-toField :: [Name] -> Int -> Type -> Q Exp
-toField ns nr t = [| $(toFieldFun ns t) $(varE (field nr)) |]
-
-toFieldFun :: [Name] -> Type -> Q Exp
-toFieldFun ns t@(ConT n)
-  | remakeName n `elem` ns = [| toRef $(conE $ remakeName n) . unI |]
-toFieldFun ns t
-  | ConT n : a <- unApp t, remakeName n `elem` ns
-                           = [| toRef $(conE $ remakeName n) . unI |]
-toFieldFun ns t@(AppT f a) = [| fmap $(toFieldFun ns a) . unD |]
-toFieldFun ns t            = [| unK |]
-
-field :: Int -> Name
-field n = mkName $ "f" ++ show n
-
-lrP :: Int -> Int -> (Q Pat -> Q Pat)
-lrP 1 0 p = p
-lrP m 0 p = conP 'L [p]
-lrP m i p = conP 'R [lrP (m-1) (i-1) p]
-
-lrE :: Int -> Int -> (Q Exp -> Q Exp)
-lrE 1 0 e = e
-lrE m 0 e = conE 'L `appE` e
-lrE m i e = conE 'R `appE` lrE (m-1) (i-1) e
-
--- Should we, under certain circumstances, maintain the module name?
-remakeName :: Name -> Name
-remakeName n = mkName (nameBase n)
diff --git a/Generics/MultiRec/Transformations/ZipChildren.hs b/Generics/MultiRec/Transformations/ZipChildren.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Transformations/ZipChildren.hs
@@ -0,0 +1,94 @@
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+
+module Generics.MultiRec.Transformations.ZipChildren where
+
+import Generics.MultiRec hiding ( show, foldM )
+import Control.Monad.State hiding ( foldM, mapM )
+import Data.Foldable ( toList )
+
+import Generics.MultiRec.CountIs
+import Generics.MultiRec.Transformations.Path
+import Generics.MultiRec.Transformations.Children
+import Generics.MultiRec.Transformations.MemoTable
+
+--------------------------------------------------------------------------------
+-- Zip immediate children
+--------------------------------------------------------------------------------
+
+zipChildrenM :: (Monad m, Fam phi, ZipChildren phi (PF phi))
+             => phi ix
+             -> (forall t. (Lookup phi (Ixs phi) t, Children phi (PF phi) t, GetChildrenTable phi (Ixs phi) t,  Eq t) => phi t -> Path phi t ix -> t -> t -> m a)
+             -> ix
+             -> ix
+             -> m [a]
+{-
+zipChildrenM p f a b = zipChildren p (\p w (I0 l) (I0 r) -> f p w l r)
+                         (\z -> Push p z Empty)
+                         (from p a) (from p b)
+-}
+zipChildrenM p f a b = zipChildren p (\p w (I0 l) (I0 r) -> f p w l r)
+                         (\z -> Push (error "oops") z Empty)
+                         (from p a) (from p b)
+
+class ZipChildren phi (f :: (* -> *) -> * -> *) where
+  zipChildren :: (Monad m)
+              => phi ix
+              -> (forall t. (Lookup phi (Ixs phi) t, Children phi (PF phi) t, GetChildrenTable phi (Ixs phi) t, Eq t)
+                  => phi t -> Path phi t ix -> r t -> r t -> m a)
+              -> (forall t. Dir f t ix -> Path phi t ix)
+              -> f r ix
+              -> f r ix
+              -> m [a]
+
+instance ( Lookup phi (Ixs phi) xi, El phi xi, Children phi (PF phi) xi
+         , GetChildrenTable phi (Ixs phi) xi, Eq xi) => ZipChildren phi (I xi) where
+  zipChildren _ f w (I l) (I r) = f proof (w CId) l r >>= \x -> return [x]
+
+instance ZipChildren phi (K a) where
+  zipChildren _ _ _ _ _ = return []
+
+instance ZipChildren phi U where
+  zipChildren _ _ _ _ _ = return []
+
+instance (ZipChildren phi f, ZipChildren phi g) => ZipChildren phi (f :+: g) where
+  zipChildren p f w (L l) (L r) = zipChildren p f (w . CL) l r
+  zipChildren p f w (R l) (R r) = zipChildren p f (w . CR) l r
+
+instance (ZipChildren phi f, ZipChildren phi g, CountIs g)
+    => ZipChildren phi (f :*: g) where
+  zipChildren p f w (l1 :*: l2) (r1 :*: r2) =
+    liftM2 (++) (zipChildren p f (\z -> w (C1 z nullY)) l1 r1)
+                (zipChildren p f (\z -> w (C2 nullX z)) l2 r2)
+      where nullX = error "nullX" -- fmap (const ()) x
+            nullY = error "nullY" -- fmap (const ()) y
+
+instance (ZipChildren phi f, Constructor c) => ZipChildren phi (C c f) where
+  zipChildren p f w (C l) (C r) = zipChildren p f (w . CC) l r
+
+instance ZipChildren phi f => ZipChildren phi (f :>: ix) where
+  zipChildren p f w (Tag l) (Tag r) = zipChildren p f (w . CTag) l r
+{-
+instance (Traversable t, ZipChildren phi f) => ZipChildren phi (t :.: f) where
+  zipChildren p f w (D l) (D r) = liftM concat $ sequence $
+                                  zipWith3 (\i -> zipChildren p f (w . TrvI i))
+                                  [0..] (toList l) (toList r)
+-}
+instance (ZipChildren phi f) => ZipChildren phi (Maybe :.: f) where
+  zipChildren p f w (D l) (D r) = liftM concat $ sequence $
+                                  zipWith3 (\i -> zipChildren p f (w . CCM))
+                                  [0..] (toList l) (toList r)
+
+instance (ZipChildren phi f) => ZipChildren phi ([] :.: f) where
+  zipChildren p f w (D l) (D r) = liftM concat $ sequence $
+                                  zipWith3 (\i -> zipChildren p f (\x -> w (CCL (ll i) x lr)))
+                                  [0..] l r
+    where ll i = replicate i (error "oops3")
+          lr = error "oops2"
diff --git a/Generics/MultiRec/Transformations/ZipperState.hs b/Generics/MultiRec/Transformations/ZipperState.hs
deleted file mode 100644
--- a/Generics/MultiRec/Transformations/ZipperState.hs
+++ /dev/null
@@ -1,72 +0,0 @@
-{-# LANGUAGE RankNTypes                 #-}
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE GADTs                      #-}
-
-module Generics.MultiRec.Transformations.ZipperState (
-  ZipperMonad, ZipperState, upMonad, downMonad, leftMonad, rightMonad, 
-  navigate, saveMonad, loadMonad, topMonad, updateMonad
-  ) where
-
-import Control.Monad
-import Control.Monad.State
-
-import Generics.MultiRec
-import Generics.MultiRec.Zipper
-import Generics.MultiRec.Any
-
---------------------------------------------------------------------------------
--- A zipper with state
---------------------------------------------------------------------------------
-
-type ZipperState phi r a = ([Any phi], Loc phi r a)
-type ZipperMonad phi r a b = StateT (ZipperState phi r a) Maybe b
-
-enterMonad :: (El phi a, Fam phi, Zipper phi (PF phi))
-           => a -> ZipperMonad phi I0 a (Any phi)
-enterMonad x = put ([], enter proof x) >> return (Any proof x)
-
-moveMonad :: (EqS phi, El phi a)
-          => (Loc phi I0 a -> Maybe (Loc phi I0 a))
-          -> ZipperMonad phi I0 a (Any phi)
-moveMonad d = StateT (\(s,l) -> do l' <- d l
-                                   let a = on (\p (I0 x) -> Any p x) l'
-                                   return (a, (s,l')))
-
-upMonad, downMonad, leftMonad, rightMonad :: (EqS phi, El phi a)
-                                          => ZipperMonad phi I0 a (Any phi)
-upMonad    = moveMonad up
-downMonad  = moveMonad down
-leftMonad  = moveMonad left
-rightMonad = moveMonad right
-
-updateMonad :: (EqS phi, El phi a)
-            => (forall xi. phi xi -> xi -> Maybe xi) 
-               -> ZipperMonad phi I0 a (Any phi)
-updateMonad f = do (s,l) <- get
-                   let l' = update (\p -> maybe (error "updateMonad") id . f p) l
-                       a  = on (\p (I0 x) -> Any p x) l'
-                   put (s,l')
-                   return a
-saveMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)
-saveMonad = do (s,l) <- get
-               let a = on (\p (I0 x) -> Any p x) l
-               put (s++[a],l)
-               return a
-
-loadMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)
-loadMonad = do (s:ss,l) <- get
-               let l' = update (\p x -> maybe x id (matchAny p s)) l
-               put (ss,l')
-               return s
-
-topMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)
-topMonad = moveMonad goUp where
-  goUp l = maybe (Just l) goUp (up l)
-
-leaveMonad :: (EqS phi, El phi a) 
-              => Loc phi I0 a -> ZipperMonad phi I0 a b -> Maybe a
-leaveMonad s m = maybe Nothing (matchAny proof) $ evalStateT (m >> topMonad) ([],s)
-
-navigate :: (Fam phi, EqS phi, El phi a, Zipper phi (PF phi))
-            => phi a -> a -> ZipperMonad phi I0 a b -> Maybe a
-navigate p x = leaveMonad (enter p x)
diff --git a/Generics/MultiRec/Zipper.hs b/Generics/MultiRec/Zipper.hs
new file mode 100644
--- /dev/null
+++ b/Generics/MultiRec/Zipper.hs
@@ -0,0 +1,220 @@
+{-# LANGUAGE FlexibleContexts      #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes            #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE EmptyDataDecls        #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Generics.MultiRec.Zipper
+-- Copyright   :  (c) 2008--2009 Universiteit Utrecht
+-- License     :  BSD3
+--
+-- Maintainer  :  generics@haskell.org
+-- Stability   :  experimental
+-- Portability :  non-portable
+--
+--
+-- The generic zipper.
+--
+-----------------------------------------------------------------------------
+
+module Generics.MultiRec.Zipper where
+
+import Prelude hiding (last)
+
+import Control.Monad
+import Control.Applicative
+import Data.Traversable
+
+import Generics.MultiRec.Base
+import Generics.MultiRec.HFunctor
+
+-- * Locations and context stacks
+
+-- | Abstract type of locations. A location contains the current focus
+-- and its context. A location is parameterized over the family of
+-- datatypes and over the type of the complete value.
+
+data Loc :: (* -> *) -> (* -> *) -> * -> * where
+  Loc :: (Fam phi, Zipper phi (PF phi))
+      => phi ix -> r ix -> Ctxs phi ix r a -> Loc phi r a
+
+data Ctxs :: (* -> *) -> * -> (* -> *) -> * -> * where
+  Empty :: Ctxs phi a r a
+  -- Push  :: phi ix -> Ctx (PF phi) b r ix -> Ctxs phi ix r a -> Ctxs phi b r a
+  Push  :: phi a -> Ctx (PF phi) a r ix -> Ctxs phi b  r a -> Ctxs phi b r ix
+
+-- * Context frames
+
+-- | Abstract type of context frames. Not required for the high-level
+-- navigation functions.
+
+data family Ctx (f :: (* -> *) -> * -> *) :: * -> (* -> *) -> * -> *
+
+data instance Ctx (K a) b r ix
+data instance Ctx U b r ix
+data instance Ctx (f :+: g) b r ix  = CL (Ctx f b r ix)
+                                    | CR (Ctx g b r ix)
+data instance Ctx (f :*: g) b r ix  = C1 (Ctx f b r ix) (g r ix)
+                                    | C2 (f r ix) (Ctx g b r ix)
+
+data instance Ctx ([]    :.: g) b r ix = CCL [g r ix] (Ctx g b r ix) [g r ix]
+data instance Ctx (Maybe :.: g) b r ix = CCM (Ctx g b r ix)
+
+
+data instance Ctx (I xi) b r ix     where CId :: Ctx (I xi) xi r ix
+data instance Ctx (f :>: xi) b r ix where
+  CTag :: Ctx f b r ix -> Ctx (f :>: ix) b r ix
+data instance Ctx (C c f) b r ix    = CC (Ctx f b r ix)
+
+-- * Contexts and locations are functors
+
+instance Zipper phi f => HFunctor phi (Ctx f b) where
+  hmapA = cmapA
+
+instance Zipper phi (PF phi) => HFunctor phi (Ctxs phi b) where
+  hmapA f p' Empty        = pure Empty
+  -- hmapA f p' (Push p c s) = liftA2 (Push p) (hmapA f p c) (hmapA f p' s)
+  hmapA f p' (Push p c s) = liftA2 (Push p) (hmapA f p' c) (hmapA f p s)
+
+instance HFunctor phi (Loc phi) where
+  hmapA f p' (Loc p x s)  = liftA2 (Loc p) (f p x) (hmapA f p' s)
+
+-- * Generic navigation functions
+
+-- | It is in general not necessary to use the generic navigation
+-- functions directly. The functions listed in the ``Interface'' section
+-- below are more user-friendly.
+--
+
+class HFunctor phi f => Zipper phi f where
+  cmapA       :: Applicative a => (forall ix. phi ix -> r ix -> a (r' ix)) ->
+                 phi ix -> Ctx f b r ix -> a (Ctx f b r' ix)
+  fill        :: phi b -> Ctx f b r ix -> r b -> f r ix
+  first, last :: (forall b. phi b -> r b -> Ctx f b r ix -> a)
+              -> f r ix -> Maybe a
+  next, prev  :: (forall b. phi b -> r b -> Ctx f b r ix -> a)
+              -> phi b -> Ctx f b r ix -> r b -> Maybe a
+
+instance El phi xi => Zipper phi (I xi) where
+  cmapA f p CId   = pure CId
+  fill    p CId x = I x
+  first f (I x)   = return (f proof x CId)
+  last  f (I x)   = return (f proof x CId)
+  next  f p CId x = Nothing
+  prev  f p CId x = Nothing
+
+instance Zipper phi (K a) where
+  cmapA f p void   = impossible void
+  fill    p void x = impossible void
+  first f (K a)    = Nothing
+  last  f (K a)    = Nothing
+  next  f p void x = impossible void
+  prev  f p void x = impossible void
+
+instance Zipper phi U where
+  cmapA f p void   = impossible void
+  fill    p void x = impossible void
+  first f U        = Nothing
+  last  f U        = Nothing
+  next  f p void x = impossible void
+  prev  f p void x = impossible void
+
+instance (Zipper phi f, Zipper phi g) => Zipper phi (f :+: g) where
+  cmapA f p (CL c)   = liftA CL (cmapA f p c)
+  cmapA f p (CR c)   = liftA CR (cmapA f p c)
+  fill    p (CL c) x = L (fill p c x)
+  fill    p (CR c) y = R (fill p c y)
+  first f (L x)      = first (\p z -> f p z . CL) x
+  first f (R y)      = first (\p z -> f p z . CR) y
+  last  f (L x)      = last  (\p z -> f p z . CL) x
+  last  f (R y)      = last  (\p z -> f p z . CR) y
+  next  f p (CL c) x = next  (\p z -> f p z . CL) p c x
+  next  f p (CR c) y = next  (\p z -> f p z . CR) p c y
+  prev  f p (CL c) x = prev  (\p z -> f p z . CL) p c x
+  prev  f p (CR c) y = prev  (\p z -> f p z . CR) p c y
+
+instance (Zipper phi f, Zipper phi g) => Zipper phi (f :*: g) where
+  cmapA f p (C1 c y)   = liftA2 C1 (cmapA f p c) (hmapA f p y)
+  cmapA f p (C2 x c)   = liftA2 C2 (hmapA f p x) (cmapA f p c)
+  fill    p (C1 c y) x = fill p c x :*: y
+  fill    p (C2 x c) y = x :*: fill p c y
+  first f (x :*: y)                =
+                first (\p z c  -> f p z (C1 c          y ))   x `mplus`
+                first (\p z c  -> f p z (C2 x          c ))   y
+  last  f (x :*: y)                 =
+                last  (\p z c  -> f p z (C2 x          c ))   y `mplus`
+                last  (\p z c  -> f p z (C1 c          y ))   x
+  next  f p (C1 c y) x =
+                next  (\p' z c' -> f p' z (C1 c'           y )) p c x `mplus`
+                first (\p' z c' -> f p' z (C2 (fill p c x) c'))     y
+  next  f p (C2 x c) y =
+                next  (\p' z c' -> f p' z (C2 x            c')) p c y
+  prev  f p (C1 c y) x =
+                prev  (\p' z c' -> f p' z (C1 c'           y )) p c x
+  prev  f p (C2 x c) y =
+                prev  (\p' z c' -> f p' z (C2 x            c')) p c y `mplus`
+                last  (\p' z c' -> f p' z (C1 c' (fill p c y)))     x
+
+-- For the time being, we support just [] and Maybe. I think we
+-- might be able to support a whole class (Foldable).
+instance (Zipper phi g) => Zipper phi ([] :.: g) where
+  cmapA f p (CCL pb c pe)   =
+    CCL <$> traverse (hmapA f p) pb <*> cmapA f p c <*> traverse (hmapA f p) pe
+  fill    p (CCL pb c pe) x =
+    D (reverse pb ++ fill p c x : pe)
+  first f (D [])            = Nothing
+  first f (D (x : xs))      = first (\p z c -> f p z (CCL [] c xs)) x
+  last  f (D xs)            =
+    case reverse xs of
+      []     -> Nothing
+      y : ys -> last (\p z c -> f p z (CCL ys c [])) y
+  next  f p (CCL pb c pe) x =
+    next (\p z c -> f p z (CCL pb c pe)) p c x `mplus`
+    case pe of
+      []     -> Nothing
+      y : ys -> first (\p' z c' -> f p' z (CCL (fill p c x : pb) c' ys)) y
+  prev  f p (CCL pb c pe) x =
+    prev (\p z c -> f p z (CCL pb c pe)) p c x `mplus`
+    case pb of
+      []     -> Nothing
+      y : ys -> last  (\p' z c' -> f p' z (CCL ys c' (fill p c x : pe))) y
+
+instance (Zipper phi g) => Zipper phi (Maybe :.: g) where
+  cmapA f p (CCM c)    =
+    CCM <$> cmapA f p c
+  fill p (CCM c) x     =
+    D (Just (fill p c x))
+  first f (D Nothing)  = Nothing
+  first f (D (Just x)) = first (\p z -> f p z . CCM) x
+  last  f (D Nothing)  = Nothing
+  last  f (D (Just x)) = last  (\p z -> f p z . CCM) x
+  next  f p (CCM c) x  = next  (\p z -> f p z . CCM) p c x
+  prev  f p (CCM c) x  = prev  (\p z -> f p z . CCM) p c x
+
+instance Zipper phi f => Zipper phi (f :>: xi) where
+  cmapA f p (CTag c)   = liftA CTag (cmapA f p c)
+  fill    p (CTag c) x = Tag (fill p c x)
+  first f (Tag x)      = first (\p z -> f p z . CTag)      x
+  last  f (Tag x)      = last  (\p z -> f p z . CTag)      x
+  next  f p (CTag c) x = next  (\p z -> f p z . CTag)  p c x
+  prev  f p (CTag c) x = prev  (\p z -> f p z . CTag)  p c x
+
+instance (Constructor c, Zipper phi f) => Zipper phi (C c f) where
+  cmapA f p (CC c)   = liftA CC (cmapA f p c)
+  fill    p (CC c) x = C (fill p c x)
+  first f (C x)      = first (\p z -> f p z . CC)     x
+  last  f (C x)      = last  (\p z -> f p z . CC)     x
+  next  f p (CC c) x = next  (\p z -> f p z . CC) p c x
+  prev  f p (CC c) x = prev  (\p z -> f p z . CC) p c x
+
+
+-- * Internal functions
+
+impossible :: a -> b
+impossible x = error "impossible"
diff --git a/Generics/Regular/Functions/GOrd.hs b/Generics/Regular/Functions/GOrd.hs
--- a/Generics/Regular/Functions/GOrd.hs
+++ b/Generics/Regular/Functions/GOrd.hs
@@ -1,41 +1,41 @@
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE FlexibleContexts           #-}
-
-module Generics.Regular.Functions.GOrd where
-
-import Generics.Regular
-import Data.Monoid (mappend)
-
---------------------------------------------------------------------------------
--- Generic Ord
---------------------------------------------------------------------------------
-
-class GOrd f where
-  comparef :: (a -> a -> Ordering) -> f a -> f a -> Ordering
-
-instance GOrd I where
-  comparef f (I x) (I y) = f x y
-
-instance Ord a => GOrd (K a) where
-  comparef _ (K x) (K y) = compare x y
-
-instance GOrd U where
-  comparef _ U U = EQ
-
-instance (GOrd f, GOrd g) => GOrd (f :+: g) where
-  comparef _ (L _) (R _) = LT
-  comparef _ (R _) (L _) = GT
-  comparef f (L x) (L y) = comparef f x y
-  comparef f (R x) (R y) = comparef f x y
-
-instance (GOrd f, GOrd g) => GOrd (f :*: g) where
-  comparef f (x1 :*: y1) (x2 :*: y2) = comparef f x1 x2 `mappend` comparef f y1 y2
-
-instance GOrd f => GOrd (C c f) where
-  comparef f (C x) (C y) = comparef f x y
-
-instance GOrd f => GOrd (S s f) where
-  comparef f (S x) (S y) = comparef f x y
-
-gcompare :: (Regular a, GOrd (PF a)) => a -> a -> Ordering
-gcompare x y = comparef gcompare (from x) (from y)
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE FlexibleContexts           #-}
+
+module Generics.Regular.Functions.GOrd where
+
+import Generics.Regular
+import Data.Monoid (mappend)
+
+--------------------------------------------------------------------------------
+-- Generic Ord
+--------------------------------------------------------------------------------
+
+class GOrd f where
+  comparef :: (a -> a -> Ordering) -> f a -> f a -> Ordering
+
+instance GOrd I where
+  comparef f (I x) (I y) = f x y
+
+instance Ord a => GOrd (K a) where
+  comparef _ (K x) (K y) = compare x y
+
+instance GOrd U where
+  comparef _ U U = EQ
+
+instance (GOrd f, GOrd g) => GOrd (f :+: g) where
+  comparef _ (L _) (R _) = LT
+  comparef _ (R _) (L _) = GT
+  comparef f (L x) (L y) = comparef f x y
+  comparef f (R x) (R y) = comparef f x y
+
+instance (GOrd f, GOrd g) => GOrd (f :*: g) where
+  comparef f (x1 :*: y1) (x2 :*: y2) = comparef f x1 x2 `mappend` comparef f y1 y2
+
+instance GOrd f => GOrd (C c f) where
+  comparef f (C x) (C y) = comparef f x y
+
+instance GOrd f => GOrd (S s f) where
+  comparef f (S x) (S y) = comparef f x y
+
+gcompare :: (Regular a, GOrd (PF a)) => a -> a -> Ordering
+gcompare x y = comparef gcompare (from x) (from y)
diff --git a/Generics/Regular/Transformations/Explicit.hs b/Generics/Regular/Transformations/Explicit.hs
deleted file mode 100644
--- a/Generics/Regular/Transformations/Explicit.hs
+++ /dev/null
@@ -1,357 +0,0 @@
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE GADTs                      #-}
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE TypeFamilies               #-}
-
-module Generics.Regular.Transformations.Explicit (
-  diff, apply, Transformation, WithRef (..), Path, Transform, 
-  HasRef (..), NiceTransformation, toNiceTransformation, fromNiceTransformation
-  ) where
-
-import Generics.Regular
-import Generics.Regular.Functions.GOrd
-import Control.Applicative ( (<|>) )
-import Control.Monad (foldM, liftM, liftM2)
-import Control.Monad.State
-import Data.Monoid (mappend)
-import qualified Data.Map as Map
-import Data.Map (Map)
-import qualified Generics.Regular.Functions.Eq as GEq
-
---------------------------------------------------------------------------------
--- Paths, annotations and edits
---------------------------------------------------------------------------------
-type Path             = [Int]
-data WithRef a b      = InR (PF a b)
-                      | Ref Path
-
-instance Functor (PF a) => Functor (WithRef a) where
-  fmap f (InR x) = InR (fmap f x)
-  fmap _ (Ref p) = Ref p
-
-type Transformation a = [ (Path, Fix (WithRef a)) ]
-
-class (Regular a, Children (PF a), CountI (PF a), Functor (PF a),
-       SEq (PF a), ExtractN (PF a), MapN (PF a), GMap (PF a), GOrd (PF a),
-       GEq.Eq (PF a)) => Transform a
-
---------------------------------------------------------------------------------
--- Patching
---------------------------------------------------------------------------------
-
--- | Apply the edits to the given tree
-apply :: Transform a => Transformation a -> a -> Maybe a
-apply e t = foldM apply' t e where
-  apply' _ ([],   c) = lookupRefs t c
-  apply' a (i:is, c) = fmap to . tmapN f . from $ a where
-    f j x | i == j     = apply' x (is,c)
-          | otherwise  = Just x
-
--- | Look up the references using the original structure
-lookupRefs :: Transform a => a -> Fix (WithRef a) -> Maybe a
-lookupRefs r (In (InR a)) = fmap to (fmapM (lookupRefs r) a)
-lookupRefs r (In (Ref p)) = extract p r
-
--- | Extract the subtree at the given path
-extract :: Transform a => Path -> a -> Maybe a
-extract p a = foldM (\x i -> extractN i $ from x) a p
-
---------------------------------------------------------------------------------
--- Diffing
---------------------------------------------------------------------------------
-data MemoKey a where
-  MemoKey :: Bool -> a -> a -> MemoKey a
-
-instance (Regular a, GEq.Eq (PF a)) => Eq (MemoKey a) where
-  (MemoKey a1 b1 c1) == (MemoKey a2 b2 c2) =
-    a1 == a2 && GEq.eq b1 b2 && GEq.eq c1 c2
-
-instance (Regular a, GEq.Eq (PF a), GOrd (PF a)) => Ord (MemoKey a) where
-  compare (MemoKey a1 b1 c1) (MemoKey a2 b2 c2) =
-    compare a1 a2 `mappend` gcompare b1 b2 `mappend` gcompare c1 c2
-
-type Memo a = Map (MemoKey a) (Transformation a)
-
--- | Find a set of edits to transform the first into the second tree
-diff :: forall a. (Transform a) => a -> a -> Transformation a
-diff a b = evalState (build False a b) Map.empty
-  where
-    childPaths :: [(a,Path)]
-    childPaths = childrenPaths a
-    buildmem :: Bool -> a -> a -> State (Memo a) (Transformation a)
-    buildmem a b c = do
-      mp <- get
-      let k = MemoKey a b c
-      case Map.lookup k mp of
-        Just r  -> return r
-        Nothing -> do
-          r <- build a b c
-          modify (Map.insert k r)
-          return r
-    build :: Bool -> a -> a -> State (Memo a) (Transformation a)
-    build False a' b' | GEq.eq a' b' = return []
-    build ins a' b' = case lookupWith GEq.eq b' childPaths of
-      Just p  -> return [([], In (Ref p))]
-      Nothing -> uses >>= maybe insert return
-        where
-          -- Construct the edits for the children based on a root
-          construct :: Bool -> a -> State (Memo a) (Maybe (Transformation a))
-          construct ins' c =
-            if shallowEq (from c) (from b')
-            then do r <- zipWithM (buildmem ins') (imChildren c) (imChildren b')
-                    return $ Just $ concat $ updateChildPaths r
-            else return Nothing
-          -- Possible edits reusing the existing tree or using a part of
-          -- the original tree. The existing tree is only used if we didn't
-          -- just insert it, since we want to keep the inserts small
-          uses :: State (Memo a) (Maybe (Transformation a))
-          uses = reuses >>= \re -> case re of
-              Just r | ins -> return re
-              _            -> construct ins a' >>= return . best re
-          -- Possible edits that include reusing a part of the original tree
-          reuses :: State (Memo a) (Maybe (Transformation a))
-          reuses = foldM f Nothing childPaths where
-            addRef p = fmap (([], In (Ref p)):)
-            f c (x,p) = construct False x >>= return . best c . addRef p
-          -- Best edit including insertion, only chosen if nothing can be reused
-          insert :: State (Memo a) (Transformation a)
-          insert = do
-            Just r <- construct True b'
-            let (r', e') = partialApply (withRefs b') r
-            return $ ([], r') : e'
-
--- | Helper function for lookup with provided compare function
-lookupWith :: (a -> a -> Bool) -> a -> [(a,b)] -> Maybe b
-lookupWith _ _ [] = Nothing
-lookupWith f a ((b,r):bs)
-  | f a b     = Just r
-  | otherwise = lookupWith f a bs
-
--- | Pick the best edit
-best :: Maybe (Transformation a) -> Maybe (Transformation a) -> Maybe (Transformation a)
-best e1 e2 = case (e1,e2) of
-  (Just e1', Just e2') -> Just (pickShortest e1' e2')
-  _                    -> e1 <|> e2
-
--- | Pick the shortest of two lists lazily
-pickShortest :: [a] -> [a] -> [a]
-pickShortest a b = if f a b then a else b
-  where f []     _      = True
-        f _      []     = False
-        f (_:xs) (_:ys) = f xs ys
-
--- | Lift a tree to a tree with references
-withRefs :: Transform a => a -> Fix (WithRef a)
-withRefs = In . InR . fmap withRefs . from
-
--- | Try to apply as much edits to the edit structure as possible
---   to make the final edit smaller
-partialApply :: Transform a =>
-                Fix (WithRef a) -> Transformation a -> (Fix (WithRef a), Transformation a)
-partialApply a [] = (a, [])
-partialApply a ((p,r):xs) = case replace p r a of
-  Just a' -> partialApply a' xs
-  Nothing -> let (a',xs') = partialApply a xs in (a', (p,r) : xs')
-
--- | Replace a subtree in an edit structure
-replace :: (Transform a, Monad m)
-           => Path -> Fix (WithRef a) -> Fix (WithRef a) -> m (Fix (WithRef a))
-replace []     r _ = return r
-replace (i:is) r a = case a of
-  In (Ref _) -> fail "Replace"
-  In (InR a') -> tmapN f a' >>= return . In . InR
-    where f j = if i == j then replace is r else return
-
--- | Extend the paths of edits for the children with the child number
-updateChildPaths :: [Transformation a] -> [Transformation a]
-updateChildPaths = zipWith (\n -> map (\(p,c) -> (n:p,c))) [0..]
-
---------------------------------------------------------------------------------
--- Shallow equality
---------------------------------------------------------------------------------
-
-class SEq f where
-  shallowEq :: f a -> f a -> Bool
-
-instance SEq I where
-  shallowEq (I _) (I _) = True
-
-instance SEq U where
-  shallowEq U U = True
-
-instance Eq a => SEq (K a) where
-  shallowEq (K a) (K b) = a == b
-
-instance (SEq f, SEq g) => SEq (f :+: g) where
-  shallowEq (L a) (L b) = shallowEq a b
-  shallowEq (R a) (R b) = shallowEq a b
-  shallowEq _     _     = False
-
-instance (SEq f, SEq g) => SEq (f :*: g) where
-  shallowEq (a :*: b) (c :*: d) = shallowEq a c && shallowEq b d
-
-instance SEq f => SEq (C c f) where
-  shallowEq (C a) (C b) = shallowEq a b
-
-instance SEq f => SEq (S s f) where
-  shallowEq (S a) (S b) = shallowEq a b
-
---------------------------------------------------------------------------------
--- ExtractN
---------------------------------------------------------------------------------
-
-class ExtractN f where
-  extractN :: Monad m => Int -> f a -> m a
-
-instance ExtractN I where
-  extractN 0 (I r) = return r
-  extractN _ (I _) = fail "extractN"
-
-instance ExtractN (K a) where
-  extractN _ (K _) = fail "extractN"
-
-instance ExtractN U where
-  extractN _ U = fail "extractN"
-
-instance (ExtractN f, ExtractN g) => ExtractN (f :+: g) where
-  extractN i (L x) = extractN i x
-  extractN i (R x) = extractN i x
-
--- Here we decrement our parameter. Does not require right-nested products
-instance (CountI f, ExtractN f, ExtractN g) => ExtractN (f :*: g) where
-  extractN i (x :*: y) = let n = countI x
-                          in if i < n then extractN i     x
-                                      else extractN (i-n) y
-
-instance ExtractN f => ExtractN (C c f) where
-  extractN i (C x) = extractN i x
-
-instance ExtractN f => ExtractN (S s f) where
-  extractN i (S x) = extractN i x
-
---------------------------------------------------------------------------------
--- MapN
---------------------------------------------------------------------------------
-
--- | Map a function with child index at a top-level structure
-tmapN :: (Monad m, MapN f) => (Int -> a -> m b) -> f a -> m (f b)
-tmapN = mapN 0
-
-class MapN f where
-  mapN :: Monad m => Int -> (Int -> a -> m b) -> f a -> m (f b)
-
-instance MapN I where
-  mapN i f (I r) = liftM I (f i r)
-
-instance MapN (K a) where
-  mapN _ _ (K x)  = liftM K (return x)
-
-instance MapN U where
-  mapN _ _ U = return U
-
-instance (MapN f, MapN g) => MapN (f :+: g) where
-  mapN i f (L x) = liftM L (mapN i f x)
-  mapN i f (R x) = liftM R (mapN i f x)
-
--- Here we increment our parameter. Does not require right-nested products
-instance (CountI f, MapN f, MapN g) => MapN (f :*: g) where
-  mapN i f (x :*: y) = liftM2 (:*:) (mapN i f x) (mapN (i + countI x) f y)
-
-instance MapN f => MapN (C c f) where
-  mapN i f (C x) = liftM C (mapN i f x)
-
-instance MapN f => MapN (S s f) where
-  mapN i f (S x) = liftM S (mapN i f x)
-
-
---------------------------------------------------------------------------------
--- CountI
---------------------------------------------------------------------------------
-
-class CountI f where
-  -- | Count the number of recursive occurrences
-  countI :: f a -> Int
-
-instance CountI I where
-  countI _ = 1
-
-instance CountI (K a) where
-  countI _ = 0
-
-instance CountI U where
-  countI _ = 0
-
-instance (CountI f, CountI g) => CountI (f :+: g) where
-  countI (L x) = countI x
-  countI (R x) = countI x
-
-instance (CountI f, CountI g) => CountI (f :*: g) where
-  countI (x :*: y) = countI x + countI y
-
-instance CountI f => CountI (C c f) where
-  countI (C x) = countI x
-
-instance CountI f => CountI (S s f) where
-  countI (S x) = countI x
-
---------------------------------------------------------------------------------
--- Children
---------------------------------------------------------------------------------
-
--- | Get the immediate children
-imChildren :: (Regular a, Children (PF a)) => a -> [a]
-imChildren = children . from
-
--- | Get all children with their paths
-childrenPaths :: (Regular a, Children (PF a)) => a -> [(a,Path)]
-childrenPaths a = (a, []) : [ (r, n : p)
-                            | (n, c) <- zip [0..] (imChildren a)
-                            , (r, p) <- childrenPaths c ]
-
-class Children f where
-  children :: f a -> [a]
-
-instance Children I where
-  children (I r) = [r]
-
-instance Children (K a) where
-  children (K _) = []
-
-instance Children U where
-  children U = []
-
-instance (Children f, Children g) => Children (f :+: g) where
-  children (L x) = children x
-  children (R x) = children x
-
-instance (Children f, Children g) => Children (f :*: g) where
-  children (x :*: y) = children x ++ children y
-
-instance Children f => Children (C c f) where
-  children (C x) = children x
-
-instance Children f => Children (S s f) where
-  children (S x) = children x
-
---------------------------------------------------------------------------------
--- Nicer interface
---------------------------------------------------------------------------------
-class HasRef a where
-  type RefRep a
-  
-  toRef   :: WithRef a (RefRep a) -> RefRep a
-  fromRef :: RefRep a -> WithRef a (RefRep a)
-
-type NiceTransformation a = [ (Path, RefRep a) ] 
-
-toNiceTransformation :: (Functor (PF a), HasRef a) 
-                        => Transformation a -> NiceTransformation a
-toNiceTransformation = map (\(p,e) -> (p, tr e)) where
-  tr = toRef . fmap tr . out
-
-fromNiceTransformation :: (Functor (PF a), HasRef a) 
-                          => NiceTransformation a -> Transformation a
-fromNiceTransformation = map (\(p,e) -> (p, fr e)) where
-  fr = In . fmap fr . fromRef
diff --git a/Generics/Regular/Transformations/Main.hs b/Generics/Regular/Transformations/Main.hs
new file mode 100644
--- /dev/null
+++ b/Generics/Regular/Transformations/Main.hs
@@ -0,0 +1,451 @@
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE ScopedTypeVariables        #-}
+{-# LANGUAGE UndecidableInstances       #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE TypeSynonymInstances       #-}
+{-# LANGUAGE OverlappingInstances       #-}
+
+module Generics.Regular.Transformations.Main
+  ( diff, apply
+  , Transformation, WithRef (..), Path (..), Transform, HasRef (..)
+  , NiceTransformation, toNiceTransformation, fromNiceTransformation
+  ) where
+
+import Prelude as P
+import Generics.Regular
+import Generics.Regular.Functions.Show hiding ( show, shows, Show )
+import qualified Generics.Regular.Functions.Show as R
+import Generics.Regular.Zipper
+import Generics.Regular.Functions.GOrd
+import Control.Applicative ( (<|>) )
+import Control.Monad (foldM, liftM, liftM2)
+import Control.Monad.State
+import Data.Monoid (mappend)
+import qualified Data.Map as Map
+import Data.Map (Map)
+import qualified Generics.Regular.Functions.Eq as GEq
+
+--------------------------------------------------------------------------------
+-- Paths, annotations and edits
+--------------------------------------------------------------------------------
+type Path  a = [Dir (PF a)]
+type Dir f = Ctx f ()
+
+data WithRef a b = InR (PF a b)
+                 | Ref (Path a)
+
+instance Functor (PF a) => Functor (WithRef a) where
+  fmap f (InR x) = InR (fmap f x)
+  fmap _ (Ref p) = Ref p -- ?
+
+type Transformation a = [ (Path a, Fix (WithRef a)) ]
+
+class (Regular a, Children (PF a), Functor (PF a), ZipChildren (PF a),
+       SEq (PF a), ExtractP (PF a), MapP (PF a), GMap (PF a), GOrd (PF a),
+       GEq.Eq (PF a)) => Transform a
+
+--------------------------------------------------------------------------------
+-- Showing paths
+--------------------------------------------------------------------------------
+newtype ConIndex = CI Int deriving (Eq, Num)
+
+instance Show ConIndex where
+  show (CI (-1)) = ""
+  show (CI n   ) = "_" ++ show n ++ " "
+
+class ShowPath f where
+  showsPrecPath :: ShowS -> ConIndex -> Int -> Dir f -> ShowS
+
+instance (ShowPath f, ShowPath g) => ShowPath (f :+: g) where
+  showsPrecPath r d n (CL p) = showsPrecPath r d n p
+  showsPrecPath r d n (CR p) = showsPrecPath r d n p
+
+instance (ShowPath f, ShowPath g, CountIs g) => ShowPath (f :*: g) where
+  -- Going left on a product is unproblematic
+  showsPrecPath r d n (C1 p _) = showsPrecPath r d n p
+  -- Going right, however, we have to increase |d| by the number of children to
+  -- our left
+  showsPrecPath r d n (C2 _ (p :: Ctx g ())) =
+    let newd = d + CI (countIs (undefined :: g r))
+    in showsPrecPath r newd n p
+
+instance (ShowPath f, Constructor c) => ShowPath (C c f) where
+  showsPrecPath r d n (CC p) = let name = conName (undefined :: C c f r)
+                               in showParen (n > 10) $ showString name
+                                                     . showsPrecPath r 0 11 p
+
+instance ShowPath (K a) where showsPrecPath _ _ _ _ = id
+instance ShowPath U     where showsPrecPath _ _ _ _ = id
+
+instance ShowPath I where
+  showsPrecPath r d n CId = shows d . r
+
+showsPrecPathC :: (ShowPath f) => ConIndex -> Int -> [Dir f] -> ShowS
+showsPrecPathC d n []     = showString "End"
+showsPrecPathC d n (p:ps) = showsPrecPath (showsPrecPathC d n ps) d n p
+
+instance (ShowPath f) => Show [Dir f] where
+  showsPrec = showsPrecPathC 0
+
+instance (ShowPath (PF a), Functor (PF a), R.Show (PF a))
+    => Show (Fix (WithRef a)) where
+  showsPrec n (In (Ref p)) = showParen (n > 10)
+                           $ showString "Ref " . showsPrec 11 p
+  showsPrec n (In (InR x)) = showParen (n > 10)
+                           $ showString "InR " . R.hshowsPrec showsPrec False 11 x
+
+spaces :: [ShowS] -> ShowS
+spaces = intersperse " "
+
+intersperse :: String -> [ShowS] -> ShowS
+intersperse s []     = id
+intersperse s [x]    = x
+intersperse s (x:xs) = x . (s ++) . spaces xs
+
+class CountIs f where
+  countIs :: f r -> Int
+
+instance CountIs I     where countIs _ = 1
+instance CountIs U     where countIs _ = 0
+instance CountIs (K a) where countIs _ = 0
+
+instance (CountIs f) => CountIs (C c f) where
+  countIs (C x) = countIs x
+
+instance (CountIs f, CountIs g) => CountIs (f :+: g) where
+  countIs (L x) = countIs x
+  countIs (R x) = countIs x
+
+instance (CountIs f, CountIs g) => CountIs (f :*: g) where
+  countIs (x :*: y) = countIs x + countIs y
+
+--------------------------------------------------------------------------------
+-- Patching
+--------------------------------------------------------------------------------
+
+-- | Apply the edits to the given tree
+apply :: Transform a => Transformation a -> a -> Maybe a
+apply e t = foldM apply' t e where
+  apply' a (p, c) = mapP (flip lookupRefs c) p a
+
+-- | Look up the references using the original structure
+lookupRefs :: Transform a => a -> Fix (WithRef a) -> Maybe a
+lookupRefs r (In (InR a)) = fmap to (fmapM (lookupRefs r) a)
+lookupRefs r (In (Ref p)) = extract p r
+
+--------------------------------------------------------------------------------
+-- Diffing
+--------------------------------------------------------------------------------
+data MemoKey a where
+  MemoKey :: Bool -> a -> a -> MemoKey a
+
+instance (Regular a, GEq.Eq (PF a)) => Eq (MemoKey a) where
+  (MemoKey a1 b1 c1) == (MemoKey a2 b2 c2) =
+    a1 == a2 && GEq.eq b1 b2 && GEq.eq c1 c2
+
+instance (Regular a, GEq.Eq (PF a), GOrd (PF a)) => Ord (MemoKey a) where
+  compare (MemoKey a1 b1 c1) (MemoKey a2 b2 c2) =
+    compare a1 a2 `mappend` gcompare b1 b2 `mappend` gcompare c1 c2
+
+type Memo a = Map (MemoKey a) (Transformation a)
+
+-- | Find a set of edits to transform the first into the second tree
+diff :: forall a. (Transform a) => a -> a -> Transformation a
+diff a b = evalState (build False a b) Map.empty
+  where
+    childPaths :: [(a,Path a)]
+    childPaths = childrenPaths a
+    buildmem :: Bool -> a -> a -> State (Memo a) (Transformation a)
+    buildmem a b c = do
+      mp <- get
+      let k = MemoKey a b c
+      case Map.lookup k mp of
+        Just r  -> return r
+        Nothing -> do
+          r <- build a b c
+          modify (Map.insert k r)
+          return r
+    build :: Bool -> a -> a -> State (Memo a) (Transformation a)
+    build False a' b' | GEq.eq a' b' = return []
+    build ins a' b' = case lookupWith GEq.eq b' childPaths of
+      Just p  -> return [([], In (Ref p))]
+      Nothing -> uses >>= maybe insert return
+        where
+          -- Construct the edits for the children based on a root
+          construct :: Bool -> a -> State (Memo a) (Maybe (Transformation a))
+          construct ins' c =
+            if shallowEq (from c) (from b')
+            then do r <- zipChildrenM (\p c1 c2 -> buildmem ins' c1 c2 >>=
+                                                   return . updateChildPaths p) c b'
+                    return $ Just $ concat r
+            else return Nothing
+          -- Possible edits reusing the existing tree or using a part of
+          -- the original tree. The existing tree is only used if we didn't
+          -- just insert it, since we want to keep the inserts small
+          uses :: State (Memo a) (Maybe (Transformation a))
+          uses = reuses >>= \re -> case re of
+              Just r | ins -> return re
+              _            -> construct ins a' >>= return . best re
+          -- Possible edits that include reusing a part of the original tree
+          reuses :: State (Memo a) (Maybe (Transformation a))
+          reuses = foldM f Nothing childPaths where
+            addRef p = fmap (([], In (Ref p)):)
+            f c (x,p) = construct False x >>= return . best c . addRef p
+          -- Best edit including insertion, only chosen if nothing can be reused
+          insert :: State (Memo a) (Transformation a)
+          insert = do
+            Just r <- construct True b'
+            let (r', e') = partialApply (withRefs b') r
+            return $ ([], r') : e'
+
+-- | Helper function for lookup with provided compare function
+lookupWith :: (a -> a -> Bool) -> a -> [(a,b)] -> Maybe b
+lookupWith _ _ [] = Nothing
+lookupWith f a ((b,r):bs)
+  | f a b     = Just r
+  | otherwise = lookupWith f a bs
+
+-- | Pick the best edit
+best :: Maybe (Transformation a) -> Maybe (Transformation a) -> Maybe (Transformation a)
+best e1 e2 = case (e1,e2) of
+  (Just e1', Just e2') -> Just (pickShortest e1' e2')
+  _                    -> e1 <|> e2
+
+-- | Pick the shortest of two lists lazily
+pickShortest :: [a] -> [a] -> [a]
+pickShortest a b = if f a b then a else b
+  where f []     _      = True
+        f _      []     = False
+        f (_:xs) (_:ys) = f xs ys
+
+-- | Lift a tree to a tree with references
+withRefs :: Transform a => a -> Fix (WithRef a)
+withRefs = In . InR . fmap withRefs . from
+
+-- | Try to apply as much edits to the edit structure as possible
+--   to make the final edit smaller
+partialApply :: Transform a =>
+                Fix (WithRef a) -> Transformation a -> (Fix (WithRef a), Transformation a)
+partialApply a [] = (a, [])
+partialApply a ((p,r):xs) = case replace p r a of
+  Just a' -> partialApply a' xs
+  Nothing -> let (a',xs') = partialApply a xs in (a', (p,r) : xs')
+
+-- | Replace a subtree in an edit structure
+replace :: (Transform a, Monad m)
+           => Path a -> Fix (WithRef a) -> Fix (WithRef a) -> m (Fix (WithRef a))
+replace p r a = mapPR (const (return r)) p a
+
+-- | Extend the paths of edits for the children with the child number
+updateChildPaths :: Path a -> Transformation a -> Transformation a
+updateChildPaths p = map (\(p2,c) -> (p ++ p2,c))
+--------------------------------------------------------------------------------
+-- Shallow equality
+--------------------------------------------------------------------------------
+
+class SEq f where
+  shallowEq :: f a -> f a -> Bool
+
+instance SEq I where
+  shallowEq (I _) (I _) = True
+
+instance SEq U where
+  shallowEq U U = True
+
+instance Eq a => SEq (K a) where
+  shallowEq (K a) (K b) = a == b
+
+instance (SEq f, SEq g) => SEq (f :+: g) where
+  shallowEq (L a) (L b) = shallowEq a b
+  shallowEq (R a) (R b) = shallowEq a b
+  shallowEq _     _     = False
+
+instance (SEq f, SEq g) => SEq (f :*: g) where
+  shallowEq (a :*: b) (c :*: d) = shallowEq a c && shallowEq b d
+
+instance SEq f => SEq (C c f) where
+  shallowEq (C a) (C b) = shallowEq a b
+
+instance SEq f => SEq (S s f) where
+  shallowEq (S a) (S b) = shallowEq a b
+
+--------------------------------------------------------------------------------
+-- Extract
+--------------------------------------------------------------------------------
+-- | Extract the subtree at the given path
+extract :: (Transform a, Monad m) => Path a -> a -> m a
+extract []     = return
+extract (p:ps) = extractP (extract ps) p . from
+
+class ExtractP f where
+  extractP :: Monad m => (a -> m a) -> Dir f -> f a -> m a
+
+instance ExtractP I where
+  extractP f CId (I r) = f r
+
+instance ExtractP (K a) where
+  extractP _ _ (K _) = fail "extractP"
+
+instance ExtractP U where
+  extractP _ _ U = fail "extractP"
+
+instance (ExtractP f, ExtractP g) => ExtractP (f :+: g) where
+  extractP f (CL p) (L x) = extractP f p x
+  extractP f (CR p) (R x) = extractP f p x
+  extractP _ _      _     = fail "extractP"
+
+instance (ExtractP f, ExtractP g) => ExtractP (f :*: g) where
+  extractP f (C1 p _) (x :*: _) = extractP f p x
+  extractP f (C2 _ p) (_ :*: y) = extractP f p y
+
+instance ExtractP f => ExtractP (C c f) where
+  extractP f (CC p) (C x) = extractP f p x
+
+instance ExtractP f => ExtractP (S s f) where
+  extractP f (CS p) (S x) = extractP f p x
+
+--------------------------------------------------------------------------------
+-- MapP
+--------------------------------------------------------------------------------
+-- | Map a function over the child in a specific path
+
+mapP :: (MapP (PF a), Monad m, Regular a) => (a -> m a) -> Path a -> a -> m a
+mapP f []     = f
+mapP f (p:ps) = liftM to . mapP' (mapP f ps) p . from
+
+-- | Version of |mapP| for trees with references
+mapPR :: (Transform a, Monad m) =>
+         (Fix (WithRef a) -> m (Fix (WithRef a)))
+         -> Path a -> Fix (WithRef a) -> m (Fix (WithRef a))
+mapPR f p (In (Ref _)) = fail "mapPR"
+mapPR f []     x            = f x
+mapPR f (p:ps) (In (InR r)) = mapP' (mapPR f ps) p r >>= return . In . InR
+
+class MapP f where
+  mapP' :: Monad m => (b -> m b) -> Dir f -> f b -> m (f b)
+
+instance MapP I where
+  mapP' f CId (I r) = liftM I (f r)
+
+instance MapP (K a) where
+  mapP' _ _ (K x)  = liftM K (return x)
+
+instance MapP U where
+  mapP' _ _ U = return U
+
+instance (MapP f, MapP g) => MapP (f :+: g) where
+  mapP' f (CL p) (L x) = liftM L (mapP' f p x)
+  mapP' f (CR p) (R x) = liftM R (mapP' f p x)
+
+instance (MapP f, MapP g) => MapP (f :*: g) where
+  mapP' f (C1 p _) (x :*: y) = liftM2 (:*:) (mapP' f p x) (return y)
+  mapP' f (C2 _ p) (x :*: y) = liftM2 (:*:) (return x) (mapP' f p y)
+
+instance MapP f => MapP (C c f) where
+  mapP' f (CC p) (C x) = liftM C (mapP' f p x)
+
+instance MapP f => MapP (S s f) where
+  mapP' f (CS p) (S x) = liftM S (mapP' f p x)
+
+--------------------------------------------------------------------------------
+-- Children
+--------------------------------------------------------------------------------
+-- | Get the immediate children
+imChildren :: (Regular a, Children (PF a)) => a -> [a]
+imChildren = map fst . children . from
+
+-- | Get all children with their paths
+childrenPaths :: (Regular a, Children (PF a)) => a -> [(a,Path a)]
+childrenPaths a = (a,[]) : [ (r, n : p)
+                           | (c, n) <- children (from a)
+                           , (r, p) <- childrenPaths c ]
+
+class Children f where
+  children :: f a -> [(a, Dir f)]
+
+instance Children I where
+  children (I r) = [(r, CId)]
+
+instance Children (K a) where
+  children (K _) = []
+
+instance Children U where
+  children U = []
+
+instance (Children f, Children g) => Children (f :+: g) where
+  children (L x) = [ (a, CL p) | (a,p) <- children x ]
+  children (R x) = [ (a, CR p) | (a,p) <- children x ]
+
+instance (Children f, Children g) => Children (f :*: g) where
+  children (x :*: y) = [ (a, C1 p nullY) | (a,p) <- children x ]
+                       ++ [ (a, C2 nullX p) | (a,p) <- children y ]
+    where nullX = error "nullX" -- fmap (const ()) x
+          nullY = error "nullY" -- fmap (const ()) y
+-- The errors above should be safe, because we're never inspecting those anyway
+
+instance Children f => Children (C c f) where
+  children (C x) = [ (a, CC p) | (a,p) <- children x ]
+
+instance Children f => Children (S s f) where
+  children (S x) = [ (a, CS p) | (a,p) <- children x ]
+
+--------------------------------------------------------------------------------
+-- ZipChildren
+--------------------------------------------------------------------------------
+zipChildrenM :: (Transform a, Monad m) => (Path a -> a -> a -> m b) -> a -> a -> m [b]
+zipChildrenM f a b = zipChildren f (:[]) (from a) (from b)
+
+class ZipChildren f where
+  zipChildren :: Monad m => (Path a -> a -> a -> m b) -> (Dir f -> Path a) -> f a -> f a -> m [b]
+
+instance ZipChildren I where
+  zipChildren f p (I a) (I b) = f (p CId) a b >>= \x -> return [x]
+
+instance ZipChildren (K a) where
+  zipChildren _ _ _ _ = return []
+
+instance ZipChildren U where
+  zipChildren _ _ _ _ = return []
+
+instance (ZipChildren f, ZipChildren g) => ZipChildren (f :+: g) where
+  zipChildren f p (L x) (L y) = zipChildren f (p . CL) x y
+  zipChildren f p (R x) (R y) = zipChildren f (p . CR) x y
+
+instance (ZipChildren f, ZipChildren g) => ZipChildren (f :*: g) where
+  zipChildren f p (x1 :*: y1) (x2 :*: y2) =
+    liftM2 (++) (zipChildren f (\x -> p $ C1 x nullY) x1 x2)
+                (zipChildren f (\x -> p $ C2 nullX x) y1 y2)
+      where nullX = error "nullX" -- fmap (const ()) x
+            nullY = error "nullY" -- fmap (const ()) y
+-- The errors above should be safe, because we're never inspecting those anyway
+
+instance ZipChildren f => ZipChildren (C c f) where
+  zipChildren f p (C x) (C y) = zipChildren f (p . CC) x y
+
+instance ZipChildren f => ZipChildren (S s f) where
+  zipChildren f p (S x) (S y) = zipChildren f (p . CS) x y
+
+--------------------------------------------------------------------------------
+-- Nicer interface
+--------------------------------------------------------------------------------
+class HasRef a where
+  type RefRep a
+
+  toRef   :: WithRef a (RefRep a) -> RefRep a
+  fromRef :: RefRep a -> WithRef a (RefRep a)
+
+type NiceTransformation a = [ (Path a, RefRep a) ]
+
+toNiceTransformation :: (Functor (PF a), HasRef a)
+                        => Transformation a -> NiceTransformation a
+toNiceTransformation = map (\(p,e) -> (p, tr e)) where
+  tr = toRef . fmap tr . out
+
+fromNiceTransformation :: (Functor (PF a), HasRef a)
+                          => NiceTransformation a -> Transformation a
+fromNiceTransformation = map (\(p,e) -> (p, fr e)) where
+  fr = In . fmap fr . fromRef
diff --git a/Generics/Regular/Transformations/RewriteRules.hs b/Generics/Regular/Transformations/RewriteRules.hs
deleted file mode 100644
--- a/Generics/Regular/Transformations/RewriteRules.hs
+++ /dev/null
@@ -1,31 +0,0 @@
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE ScopedTypeVariables        #-}
-
-module Generics.Regular.Transformations.RewriteRules (
-  Transform, Transformation, apply
-  ) where
-
-import Generics.Regular
-import Generics.Regular.Rewriting
-import Generics.Regular.Zipper
-
-import Control.Monad ( foldM )
-
---------------------------------------------------------------------------------
--- Patch
---------------------------------------------------------------------------------
--- Basically, a class synonym
-class (Regular a, Rewrite a, Zipper (PF a)) => Transform a
-instance Transform a => Rewrite a
-
--- An edit is a list of:
-type Transformation a = [ ( Loc a -> Maybe (Loc a) -- A path to the location to edit
-                          , Rule a) ]              -- The rewrite rule to apply there
-
--- Patching is terribly simple: at the given locations, apply all the rules,
--- then exit the zipper.
-apply :: forall a. (Transform a) => Transformation a -> a -> Maybe a
-apply rs = fmap leave . flip (foldM appRule) rs . enter
-  where appRule a (l,r) = l a >>= updateM (rewriteM r)
diff --git a/Generics/Regular/Transformations/TH.hs b/Generics/Regular/Transformations/TH.hs
deleted file mode 100644
--- a/Generics/Regular/Transformations/TH.hs
+++ /dev/null
@@ -1,191 +0,0 @@
-{-# LANGUAGE TemplateHaskell            #-}
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE UndecidableInstances       #-}
-
-module Generics.Regular.Transformations.TH ( 
-  deriveRefRep, prefix, postfix
-  ) where
-
-import Generics.Regular
-import Language.Haskell.TH
-import Generics.Regular.Transformations.Explicit
-
--- Code taken from regular library and adapted to work with transformations
-
--- | Derive data type with references and 'HasRef' instance. For a data type
---   N the name of the constructor for a reference is RefN, and the given
---   function is used to change the rest of the constructors and the data
---   type name itself. For example, for the following definition:
---
--- > data Tree = Leaf Int | Bin Tree Tree
--- > $(deriveRefRep ''Tree (postfix "R"))
---
--- The following data type is generated:
---
--- > data TreeR = LeafR Int | BinR TreeR TreeR | RefTree Path
--- > instance HasRef Tree
-deriveRefRep :: Name -> (Name -> Name) -> Q [Dec]
-deriveRefRep t namef = do
-  d <- deriveData t namef
-  ins <- deriveInst t namef
-  return [d,ins]
-
-deriveData :: Name -> (Name -> Name) -> Q Dec
-deriveData t namef = do
-  let nm = namef t
-  i <- reify t
-  cons <- case i of
-    TyConI (DataD _ _ _ cs _) -> mapM (mkCon t namef nm) cs
-  r <- normalC (prefix "Ref" t) [return (NotStrict, ConT ''Path)]
-  dataD (cxt []) nm (typeVariables i) (map return $ r : cons) []
-
-mkCon :: Name -> (Name -> Name) -> Name -> Con -> Q Con
-mkCon t namef repname (NormalC a b) = normalC (namef a) (map f b) where
-  f :: (Strict, Type) -> Q (Strict, Type)
-  f (s,t') | t' == ConT t = return (s, ConT repname)
-           | otherwise    = return (s, t')
-
-prefix :: String -> Name -> Name
-prefix pref n = mkName $ pref ++ nameBase n
-
-postfix :: String -> Name -> Name
-postfix post n = mkName $ nameBase n ++ post
-
-deriveInst :: Name -> (Name -> Name) -> Q Dec
-deriveInst t namef =
-  do
-    i <- reify t
-    let typ = foldl (\a -> AppT a . VarT . tyVarBndrToName) (ConT t) (typeVariables i)
-    let rn = prefix "Ref" t
-    fcs <- mkFrom t 1 0 namef rn t
-    tcs <- mkTo   t 1 0 namef rn t
-    let typ' = return $ foldl (\a -> AppT a . VarT . tyVarBndrToName) (ConT $ namef t) (typeVariables i)      
-    instanceD (cxt []) (conT ''HasRef `appT` return typ)
-        [tySynInstD ''RefRep [return typ] typ', funD 'toRef tcs, funD 'fromRef fcs]
-
-lrE :: Int -> Int -> (Q Exp -> Q Exp)
-lrE 1 0 e = e
-lrE m 0 e = conE 'L `appE` e
-lrE m i e = conE 'R `appE` lrE (m-1) (i-1) e
-
-tyVarBndrToName :: TyVarBndr -> Name
-tyVarBndrToName (PlainTV  name)   = name
-tyVarBndrToName (KindedTV name _) = name
-
-typeVariables :: Info -> [TyVarBndr]
-typeVariables (TyConI (DataD    _ _ tv _ _)) = tv
-typeVariables (TyConI (NewtypeD _ _ tv _ _)) = tv
-typeVariables _                           = []
-
-mkFrom :: Name -> Int -> Int -> (Name -> Name) -> Name -> Name -> Q [Q Clause]
-mkFrom ns m i namef refname n = do
-  let wrapE e = conE 'InR `appE` lrE m i e
-  i <- reify n
-  let r = clause [conP refname [varP $ field 0]] (normalB $ conE 'Ref `appE` varE (field 0)) []
-  let b = case i of
-        TyConI (DataD _ dt vs cs _) ->
-          zipWith (fromCon wrapE ns namef (dt, map tyVarBndrToName vs) (length cs)) [0..] cs
-        TyConI (NewtypeD _ dt vs c _) ->
-          [fromCon wrapE ns namef (dt, map tyVarBndrToName vs) 1 0 c]
-        TyConI (TySynD t _ _) ->
-          [clause [varP (field 0)] (normalB (wrapE $ conE 'K `appE` varE (field 0))) []]
-        _ -> error "unknown construct"
-  return $ r : b
-
-mkTo :: Name -> Int -> Int -> (Name -> Name) -> Name -> Name -> Q [Q Clause]
-mkTo ns m i namef refname n = do
-  let wrapP p = conP 'InR [lrP m i p]
-  i <- reify n
-  let r = clause [conP 'Ref [varP $ field 0]] (normalB $ conE refname `appE` varE (field 0)) []
-  let b = case i of
-                TyConI (DataD _ dt vs cs _) ->
-                  zipWith (toCon wrapP ns namef (dt, map tyVarBndrToName vs) (length cs)) [0..] cs
-                TyConI (NewtypeD _ dt vs c _) ->
-                  [toCon wrapP ns namef (dt, map tyVarBndrToName vs) 1 0 c]
-                TyConI (TySynD t _ _) ->
-                  [clause [wrapP $ conP 'K [varP (field 0)]] (normalB $ varE (field 0)) []]
-                _ -> error "unknown construct" 
-  return $ r : b
-
-fromCon :: (Q Exp -> Q Exp) -> Name -> (Name -> Name) -> (Name, [Name]) -> Int -> Int -> Con -> Q Clause
-fromCon wrap ns namef (dt, vs) m i (NormalC cn []) =
-    clause
-      [conP (namef cn) []]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []
-fromCon wrap ns namef (dt, vs) m i (NormalC cn fs) =
-    clause
-      [conP (namef cn) (map (varP . field) [0..length fs - 1])]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField (dt, vs)) [0..] (map snd fs))) []
-  where
-    prod x y = conE '(:*:) `appE` x `appE` y
-fromCon wrap ns namef (dt, vs) m i r@(RecC cn []) =
-    clause
-      [conP (namef cn) []]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []
-fromCon wrap ns namef (dt, vs) m i r@(RecC cn fs) =
-    clause
-      [conP (namef cn) (map (varP . field) [0..length fs - 1])]
-      (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField' (dt, vs)) [0..] fs)) []
-  where
-    prod x y = conE '(:*:) `appE` x `appE` y
-fromCon wrap ns namef (dt, vs) m i (InfixC t1 cn t2) =
-  fromCon wrap ns namef (dt, vs) m i (NormalC cn [t1,t2])
-
-fromField :: (Name, [Name]) -> Int -> Type -> Q Exp
-fromField (dt, vs) nr t | t == dataDeclToType (dt, vs) = 
-  conE 'I `appE` varE (field nr)
-fromField (dt, vs) nr t                                = 
-  conE 'K `appE` varE (field nr)
-
-fromField' :: (Name, [Name]) -> Int -> (Name, Strict, Type) -> Q Exp
-fromField' (dt, vs) nr (_, _, t) | t == dataDeclToType (dt, vs) =
-  conE 'S `appE` (conE 'I `appE` varE (field nr))
-fromField' (dt, vs) nr (_, _, t)                                =
-  conE 'S `appE` (conE 'K `appE` varE (field nr))
-
-toCon :: (Q Pat -> Q Pat) -> Name -> (Name -> Name) -> (Name, [Name]) -> Int -> Int -> Con -> Q Clause
-toCon wrap ns namef (dt, vs) m i (NormalC cn []) =
-    clause
-      [wrap $ lrP m i $ conP 'C [conP 'U []]]
-      (normalB $ conE $ namef cn) []
-toCon wrap ns namef (dt, vs) m i (NormalC cn fs) =
-    -- runIO (putStrLn ("constructor " ++ show ix)) >>
-    clause
-      [wrap $ lrP m i $ conP 'C [foldr1 prod (zipWith (toField (dt, vs)) [0..] (map snd fs))]]
-      (normalB $ foldl appE (conE $ namef cn) (map (varE . field) [0..length fs - 1])) []
-  where
-    prod x y = conP '(:*:) [x,y]
-toCon wrap ns namef (dt, vs) m i r@(RecC cn []) =
-    clause
-      [wrap $ lrP m i $ conP 'C [conP 'U []]]
-      (normalB $ conE $ namef cn) []
-toCon wrap ns namef (dt, vs) m i r@(RecC cn fs) =
-    clause
-      [wrap $ lrP m i $ conP 'C [foldr1 prod (zipWith (toField' (dt, vs)) [0..] fs)]]
-      (normalB $ foldl appE (conE $ namef cn) (map (varE . field) [0..length fs - 1])) []
-  where
-    prod x y = conP '(:*:) [x,y]
-toCon wrap ns namef (dt, vs) m i (InfixC t1 cn t2) =
-  toCon wrap ns namef (dt, vs) m i (NormalC cn [t1,t2])
-
-toField :: (Name, [Name]) -> Int -> Type -> Q Pat
-toField (dt, vs) nr t | t == dataDeclToType (dt, vs) = 
-  conP 'I [varP (field nr)]
-toField (dt, vs) nr t                                = 
-  conP 'K [varP (field nr)]
-
-toField' :: (Name, [Name]) -> Int -> (Name, Strict, Type) -> Q Pat
-toField' (dt, vs) nr (_, _, t) | t == dataDeclToType (dt, vs) = conP 'S [conP 'I [varP (field nr)]]
-toField' (dt, vs) nr (_, _, t)                                = conP 'S [conP 'K [varP (field nr)]]
-
-field :: Int -> Name
-field n = mkName $ "f" ++ show n
-
-lrP :: Int -> Int -> (Q Pat -> Q Pat)
-lrP 1 0 p = p
-lrP m 0 p = conP 'L [p]
-lrP m i p = conP 'R [lrP (m-1) (i-1) p]
-
-dataDeclToType :: (Name, [Name]) -> Type
-dataDeclToType (dt, vs) = foldl (\a b -> AppT a (VarT b)) (ConT dt) vs
diff --git a/Generics/Regular/Transformations/ZipperState.hs b/Generics/Regular/Transformations/ZipperState.hs
deleted file mode 100644
--- a/Generics/Regular/Transformations/ZipperState.hs
+++ /dev/null
@@ -1,57 +0,0 @@
-{-# LANGUAGE FlexibleContexts           #-}
-
-module Generics.Regular.Transformations.ZipperState (
-  ZipperMonad, ZipperState, upMonad, downMonad, leftMonad, rightMonad, 
-  navigate, saveMonad, loadMonad, topMonad, updateMonad
-  ) where
-
-import Control.Monad.State (StateT (..), evalStateT, get, put)
-
-import Generics.Regular.Zipper
-import Generics.Regular ( Regular, PF )
-
---------------------------------------------------------------------------------
--- A zipper with state
---------------------------------------------------------------------------------
-
-type ZipperState a = ([a], Loc a)
-type ZipperMonad a b = StateT (ZipperState a) Maybe b
-
-moveMonad :: (Loc a -> Maybe (Loc a)) -> ZipperMonad a a
-moveMonad m = StateT (\(s,l) -> m l >>= (\l' -> return (on l', (s,l'))))
-
-upMonad, downMonad, leftMonad, rightMonad :: ZipperMonad a a
-upMonad    = moveMonad up
-downMonad  = moveMonad down
-leftMonad  = moveMonad left
-rightMonad = moveMonad right
-
-updateMonad :: (a -> a) -> ZipperMonad a a
-updateMonad f = do (s,l) <- get
-                   let l' = update f l
-                   put (s,l')
-                   return (on l')
-
-saveMonad :: ZipperMonad a a
-saveMonad = do (s,l) <- get
-               let a = on l
-               put (s++[a],l)
-               return a
-
-loadMonad :: ZipperMonad a a
-loadMonad = do (s:ss,l) <- get
-               let l' = update (const s) l
-               put (ss,l')
-               return (on l')
-
-topMonad :: ZipperMonad a a
-topMonad = do (_, Loc x l) <- get
-              case l of
-                [] -> return x
-                _  -> upMonad >> topMonad
-
-leaveMonad :: Loc a -> ZipperMonad a b -> Maybe a
-leaveMonad s m = evalStateT (m >> topMonad) ([],s)
-
-navigate :: (Regular a, Zipper (PF a)) => a -> ZipperMonad a b -> Maybe a
-navigate x m = leaveMonad (enter x) m
diff --git a/Generics/Regular/Zipper.hs b/Generics/Regular/Zipper.hs
--- a/Generics/Regular/Zipper.hs
+++ b/Generics/Regular/Zipper.hs
@@ -1,245 +1,244 @@
-{-# LANGUAGE FlexibleContexts           #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE GADTs                      #-}
-{-# LANGUAGE KindSignatures             #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE RankNTypes                 #-}
-{-# LANGUAGE TypeFamilies               #-}
-{-# LANGUAGE TypeOperators              #-}
-{-# LANGUAGE EmptyDataDecls             #-}
-{-# LANGUAGE TupleSections              #-}
-
-module Generics.Regular.Zipper
-  (-- * Locations
-   Loc(..),
-   -- * Context frames
-   Ctx(),
-   -- * Generic zipper class
-   Zipper(..),
-   -- * Interface
-   enter,
-   down, down', up, right, left,
-   -- dfnext, dfprev,
-   leave, on, update, updateM
-
-  )
-  where
-
-import Prelude hiding (last)
-
-import Control.Monad
-import Control.Monad.State
-import Control.Applicative
-import Data.Maybe
-import Data.Traversable
-
-import Generics.Regular hiding (left, right)
-
--- * Locations and context stacks
-
--- | Abstract type of locations. A location contains the current focus
--- and its context. A location is parameterized over the family of
--- datatypes and over the type of the complete value.
-
-data Loc :: * -> * where
-  Loc :: (Regular a, Zipper (PF a)) => a -> [Ctx (PF a) a] -> Loc a
-
--- * Context frames
-
--- | Abstract type of context frames. Not required for the high-level
--- navigation functions.
-
-data family Ctx (f :: * -> *) :: * -> *
-
-data instance Ctx (K a) r
-data instance Ctx U r
-data instance Ctx (f :+: g) r = CL (Ctx f r) | CR (Ctx g r)
-data instance Ctx (f :*: g) r = C1 (Ctx f r) (g r) | C2 (f r) (Ctx g r)
-data instance Ctx I r = CId
-data instance Ctx (C c f) r = CC (Ctx f r)
-data instance Ctx (S s f) r = CS (Ctx f r)
-
--- * Contexts and locations are functors
-
-instance Zipper f => Functor (Ctx f) where
-  fmap = cmap
-
--- instance Functor (Loc f) where
-  -- fmap f (Loc p x)  = Loc (f p) (map (fmap f) x)
-
--- * Generic navigation functions
-
--- | It is in general not necessary to use the generic navigation
--- functions directly. The functions listed in the ``Interface'' section
--- below are more user-friendly.
---
-
-class Functor f => Zipper f where
-  cmap        :: (a -> b) -> Ctx f a -> Ctx f b
-  fill        :: Ctx f a -> a -> f a
-  first, last :: f a -> Maybe (a, Ctx f a)
-  next, prev  :: Ctx f a -> a -> Maybe (a, Ctx f a)
-
-instance Zipper I where
-  cmap  f CId = CId
-  fill  CId x = I x
-  first (I x) = Just (x, CId)
-  last  (I x) = Just (x, CId)
-  next  CId x = Nothing
-  prev  CId x = Nothing
-
-instance Zipper (K a) where
-  cmap f void = impossible void
-  fill void x = impossible void
-  first (K a) = Nothing
-  last  (K a) = Nothing
-  next  void x = impossible void
-  prev  void x = impossible void
-
-instance Zipper U where
-  cmap f void = impossible void
-  fill void x = impossible void
-  first U      = Nothing
-  last  U      = Nothing
-  next  void x = impossible void
-  prev  void x = impossible void
-
-instance (Zipper f, Zipper g) => Zipper (f :+: g) where
-  cmap f (CL c)   = CL (cmap f c)
-  cmap f (CR c)   = CR (cmap f c)
-  fill (CL c) x   = L (fill c x)
-  fill (CR c) y   = R (fill c y)
-  first (L x)     = first x >>= return . fmap CL
-  first (R x)     = first x >>= return . fmap CR
-  last  (L x)     = last x >>= return . fmap CL
-  last  (R x)     = last x >>= return . fmap CR
-  next  (CL c) x = next c x >>= return . fmap CL
-  next  (CR c) x = next c x >>= return . fmap CR
-  prev  (CL c) x = prev c x >>= return . fmap CL
-  prev  (CR c) x = prev c x >>= return . fmap CR
-
-instance (Zipper f, Zipper g) => Zipper (f :*: g) where
-  cmap f (C1 c y)   = C1 (cmap f c) (fmap f y)
-  cmap f (C2 x c)   = C2 (fmap f x) (cmap f c)
-  fill (C1 c y) x = fill c x :*: y
-  fill (C2 x c) y = x :*: fill c y
-  first (x :*: y) =         fmap (fmap (flip C1 y)) (first x)
-                    `mplus` fmap (fmap (C2 x))      (first y)
-  last  (x :*: y) =         fmap (fmap (C2 x))      (last  y)
-                    `mplus` fmap (fmap (flip C1 y)) (last  x)
-  next (C1 c y) z =         (fmap (flip C1 y)     <$> next c z)
-                    `mplus` (fmap (C2 (fill c z)) <$> first y)
-  next (C2 x c) z =          fmap (C2 x)          <$> next c z
-  prev (C1 c y) z =          fmap (flip C1 y)     <$> prev c z
-  prev (C2 x c) z =         (fmap (C2 x)               <$> prev c z)
-                    `mplus` (fmap (flip C1 (fill c z)) <$> last x)
-
-instance (Zipper f) => Zipper (C c f) where
-  cmap f (CC c)   = CC (cmap f c)
-  fill   (CC c) x = C (fill c x)
-  first  (C x)    = first  x >>= return . fmap CC
-  last   (C x)    = last   x >>= return . fmap CC
-  next   (CC c) x = next c x >>= return . fmap CC
-  prev   (CC c) x = prev c x >>= return . fmap CC
-
-instance (Zipper f) => Zipper (S s f) where
-  cmap f (CS c)   = CS (cmap f c)
-  fill   (CS c) x = S (fill c x)
-  first  (S x)    = first  x >>= return . fmap CS
-  last   (S x)    = last   x >>= return . fmap CS
-  next   (CS c) x = next c x >>= return . fmap CS
-  prev   (CS c) x = prev c x >>= return . fmap CS
-
--- * Interface
-
--- ** Introduction
-
--- | Start navigating a datastructure. Returns a location that
--- focuses the entire value and has an empty context.
-enter :: (Regular a, Zipper (PF a)) => a -> Loc a
-enter x = Loc x []
-
--- ** Navigation
-
--- | Move down to the leftmost child. Returns 'Nothing' if the
--- current focus is a leaf.
-down :: Loc a -> Maybe (Loc a)
-down (Loc x cs) = first (from x) >>= \(a,c) -> return (Loc a (c:cs))
-
--- | Move down to the rightmost child. Returns 'Nothing' if the
--- current focus is a leaf.
-down' :: Loc a -> Maybe (Loc a)
-down' (Loc x cs) = last (from x) >>= \(a,c) -> return (Loc a (c:cs))
-
--- | Move up to the parent. Returns 'Nothing' if the current
--- focus is the root.
-up :: Loc a -> Maybe (Loc a)
-up (Loc x [])     = Nothing
-up (Loc x (c:cs)) = return (Loc (to (fill c x)) cs)
-
--- | Move to the right sibling. Returns 'Nothing' if the current
--- focus is the rightmost sibling.
-right :: Loc a -> Maybe (Loc a)
-right (Loc x []    ) = Nothing
-right (Loc x (c:cs)) = next c x >>= \(a,c') -> return (Loc a (c':cs))
-
--- | Move to the left sibling. Returns 'Nothing' if the current
--- focus is the leftmost sibling.
-left :: Loc a -> Maybe (Loc a)
-left (Loc x []    ) = Nothing
-left (Loc x (c:cs)) = prev c x >>= \(a,c') -> return (Loc a (c':cs))
-
-
--- ** Derived navigation.
-{-
-df :: (a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a
-df d u lr l =
-  case d l of
-    Nothing -> df' l
-    r       -> r
- where
-  df' l =
-    case lr l of
-      Nothing -> case u l of
-                   Nothing -> Nothing
-                   Just l' -> df' l'
-      r       -> r
-
--- | Move through all positions in depth-first left-to-right order.
-dfnext :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
-dfnext = df down up right
-
--- | Move through all positions in depth-first right-to-left order.
-dfprev :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
-dfprev = df down' up left
--}
-
--- | Utility
--- navigate :: (Regular a, Zipper (PF a))
-         -- => a -> (Loc a -> Maybe (Loc a)) -> Loc a
--- navigate a f = fromJust $ f (enter a)
-
--- ** Elimination
-
--- | Return the entire value, independent of the current focus.
-leave :: Loc a -> a
-leave (Loc x []) = x
-leave loc        = leave (fromJust (up loc))
-
--- | Operate on the current focus. This function can be used to
--- extract the current point of focus.
-on :: Loc a -> a
-on (Loc x _) = x
-
--- | Update the current focus without changing its type.
-update :: (a -> a) -> Loc a -> Loc a
-update f (Loc x cs) = Loc (f x) cs
-
--- | Update the current focus without changing its type.
-updateM :: Monad m => (a -> m a) -> Loc a -> m (Loc a)
-updateM f (Loc x cs) = f x >>= \y -> return (Loc y cs)
-
--- * Internal functions
-
-impossible :: a -> b
-impossible x = x `seq` error "impossible"
+{-# LANGUAGE FlexibleContexts           #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GADTs                      #-}
+{-# LANGUAGE KindSignatures             #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE RankNTypes                 #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE TypeOperators              #-}
+{-# LANGUAGE EmptyDataDecls             #-}
+{-# LANGUAGE TupleSections              #-}
+
+module Generics.Regular.Zipper
+  (-- * Locations
+   Loc(..),
+   -- * Context frames
+   Ctx(..),
+   -- * Generic zipper class
+   Zipper(..),
+   -- * Interface
+   enter,
+   down, down', up, right, left,
+   -- dfnext, dfprev,
+   leave, on, update, updateM
+
+  )
+  where
+
+import Prelude hiding (last)
+
+import Control.Monad
+import Control.Monad.State
+import Control.Applicative
+import Data.Maybe
+
+import Generics.Regular hiding (left, right)
+
+-- * Locations and context stacks
+
+-- | Abstract type of locations. A location contains the current focus
+-- and its context. A location is parameterized over the family of
+-- datatypes and over the type of the complete value.
+
+data Loc :: * -> * where
+  Loc :: (Regular a, Zipper (PF a)) => a -> [Ctx (PF a) a] -> Loc a
+
+-- * Context frames
+
+-- | Abstract type of context frames. Not required for the high-level
+-- navigation functions.
+
+data family Ctx (f :: * -> *) :: * -> *
+
+data instance Ctx (K a) r
+data instance Ctx U r
+data instance Ctx (f :+: g) r = CL (Ctx f r) | CR (Ctx g r)
+data instance Ctx (f :*: g) r = C1 (Ctx f r) (g r) | C2 (f r) (Ctx g r)
+data instance Ctx I r = CId
+data instance Ctx (C c f) r = CC (Ctx f r)
+data instance Ctx (S s f) r = CS (Ctx f r)
+
+-- * Contexts and locations are functors
+
+instance Zipper f => Functor (Ctx f) where
+  fmap = cmap
+
+-- instance Functor (Loc f) where
+  -- fmap f (Loc p x)  = Loc (f p) (map (fmap f) x)
+
+-- * Generic navigation functions
+
+-- | It is in general not necessary to use the generic navigation
+-- functions directly. The functions listed in the ``Interface'' section
+-- below are more user-friendly.
+--
+
+class Functor f => Zipper f where
+  cmap        :: (a -> b) -> Ctx f a -> Ctx f b
+  fill        :: Ctx f a -> a -> f a
+  first, last :: f a -> Maybe (a, Ctx f a)
+  next, prev  :: Ctx f a -> a -> Maybe (a, Ctx f a)
+
+instance Zipper I where
+  cmap  f CId = CId
+  fill  CId x = I x
+  first (I x) = Just (x, CId)
+  last  (I x) = Just (x, CId)
+  next  CId x = Nothing
+  prev  CId x = Nothing
+
+instance Zipper (K a) where
+  cmap f void = impossible void
+  fill void x = impossible void
+  first (K a) = Nothing
+  last  (K a) = Nothing
+  next  void x = impossible void
+  prev  void x = impossible void
+
+instance Zipper U where
+  cmap f void = impossible void
+  fill void x = impossible void
+  first U      = Nothing
+  last  U      = Nothing
+  next  void x = impossible void
+  prev  void x = impossible void
+
+instance (Zipper f, Zipper g) => Zipper (f :+: g) where
+  cmap f (CL c)   = CL (cmap f c)
+  cmap f (CR c)   = CR (cmap f c)
+  fill (CL c) x   = L (fill c x)
+  fill (CR c) y   = R (fill c y)
+  first (L x)     = first x >>= return . fmap CL
+  first (R x)     = first x >>= return . fmap CR
+  last  (L x)     = last x >>= return . fmap CL
+  last  (R x)     = last x >>= return . fmap CR
+  next  (CL c) x = next c x >>= return . fmap CL
+  next  (CR c) x = next c x >>= return . fmap CR
+  prev  (CL c) x = prev c x >>= return . fmap CL
+  prev  (CR c) x = prev c x >>= return . fmap CR
+
+instance (Zipper f, Zipper g) => Zipper (f :*: g) where
+  cmap f (C1 c y)   = C1 (cmap f c) (fmap f y)
+  cmap f (C2 x c)   = C2 (fmap f x) (cmap f c)
+  fill (C1 c y) x = fill c x :*: y
+  fill (C2 x c) y = x :*: fill c y
+  first (x :*: y) =         fmap (fmap (flip C1 y)) (first x)
+                    `mplus` fmap (fmap (C2 x))      (first y)
+  last  (x :*: y) =         fmap (fmap (C2 x))      (last  y)
+                    `mplus` fmap (fmap (flip C1 y)) (last  x)
+  next (C1 c y) z =         (fmap (flip C1 y)     <$> next c z)
+                    `mplus` (fmap (C2 (fill c z)) <$> first y)
+  next (C2 x c) z =          fmap (C2 x)          <$> next c z
+  prev (C1 c y) z =          fmap (flip C1 y)     <$> prev c z
+  prev (C2 x c) z =         (fmap (C2 x)               <$> prev c z)
+                    `mplus` (fmap (flip C1 (fill c z)) <$> last x)
+
+instance (Zipper f) => Zipper (C c f) where
+  cmap f (CC c)   = CC (cmap f c)
+  fill   (CC c) x = C (fill c x)
+  first  (C x)    = first  x >>= return . fmap CC
+  last   (C x)    = last   x >>= return . fmap CC
+  next   (CC c) x = next c x >>= return . fmap CC
+  prev   (CC c) x = prev c x >>= return . fmap CC
+
+instance (Zipper f) => Zipper (S s f) where
+  cmap f (CS c)   = CS (cmap f c)
+  fill   (CS c) x = S (fill c x)
+  first  (S x)    = first  x >>= return . fmap CS
+  last   (S x)    = last   x >>= return . fmap CS
+  next   (CS c) x = next c x >>= return . fmap CS
+  prev   (CS c) x = prev c x >>= return . fmap CS
+
+-- * Interface
+
+-- ** Introduction
+
+-- | Start navigating a datastructure. Returns a location that
+-- focuses the entire value and has an empty context.
+enter :: (Regular a, Zipper (PF a)) => a -> Loc a
+enter x = Loc x []
+
+-- ** Navigation
+
+-- | Move down to the leftmost child. Returns 'Nothing' if the
+-- current focus is a leaf.
+down :: Loc a -> Maybe (Loc a)
+down (Loc x cs) = first (from x) >>= \(a,c) -> return (Loc a (c:cs))
+
+-- | Move down to the rightmost child. Returns 'Nothing' if the
+-- current focus is a leaf.
+down' :: Loc a -> Maybe (Loc a)
+down' (Loc x cs) = last (from x) >>= \(a,c) -> return (Loc a (c:cs))
+
+-- | Move up to the parent. Returns 'Nothing' if the current
+-- focus is the root.
+up :: Loc a -> Maybe (Loc a)
+up (Loc x [])     = Nothing
+up (Loc x (c:cs)) = return (Loc (to (fill c x)) cs)
+
+-- | Move to the right sibling. Returns 'Nothing' if the current
+-- focus is the rightmost sibling.
+right :: Loc a -> Maybe (Loc a)
+right (Loc x []    ) = Nothing
+right (Loc x (c:cs)) = next c x >>= \(a,c') -> return (Loc a (c':cs))
+
+-- | Move to the left sibling. Returns 'Nothing' if the current
+-- focus is the leftmost sibling.
+left :: Loc a -> Maybe (Loc a)
+left (Loc x []    ) = Nothing
+left (Loc x (c:cs)) = prev c x >>= \(a,c') -> return (Loc a (c':cs))
+
+
+-- ** Derived navigation.
+{-
+df :: (a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a
+df d u lr l =
+  case d l of
+    Nothing -> df' l
+    r       -> r
+ where
+  df' l =
+    case lr l of
+      Nothing -> case u l of
+                   Nothing -> Nothing
+                   Just l' -> df' l'
+      r       -> r
+
+-- | Move through all positions in depth-first left-to-right order.
+dfnext :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
+dfnext = df down up right
+
+-- | Move through all positions in depth-first right-to-left order.
+dfprev :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
+dfprev = df down' up left
+-}
+
+-- | Utility
+-- navigate :: (Regular a, Zipper (PF a))
+         -- => a -> (Loc a -> Maybe (Loc a)) -> Loc a
+-- navigate a f = fromJust $ f (enter a)
+
+-- ** Elimination
+
+-- | Return the entire value, independent of the current focus.
+leave :: Loc a -> a
+leave (Loc x []) = x
+leave loc        = leave (fromJust (up loc))
+
+-- | Operate on the current focus. This function can be used to
+-- extract the current point of focus.
+on :: Loc a -> a
+on (Loc x _) = x
+
+-- | Update the current focus without changing its type.
+update :: (a -> a) -> Loc a -> Loc a
+update f (Loc x cs) = Loc (f x) cs
+
+-- | Update the current focus without changing its type.
+updateM :: Monad m => (a -> m a) -> Loc a -> m (Loc a)
+updateM f (Loc x cs) = f x >>= \y -> return (Loc y cs)
+
+-- * Internal functions
+
+impossible :: a -> b
+impossible x = x `seq` error "impossible"
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,675 +1,675 @@
-              GNU GENERAL PUBLIC LICENSE
-                Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-                     Preamble
-
-  The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
-  The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works.  By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users.  We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors.  You can apply it to
-your programs, too.
-
-  When we speak of free software, we are referring to freedom, not
-price.  Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
-  To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights.  Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
-  For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received.  You must make sure that they, too, receive
-or can get the source code.  And you must show them these terms so they
-know their rights.
-
-  Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
-  For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software.  For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
-  Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so.  This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software.  The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable.  Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products.  If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
-  Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary.  To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
-  The precise terms and conditions for copying, distribution and
-modification follow.
-
-                TERMS AND CONDITIONS
-
-  0. Definitions.
-
-  "This License" refers to version 3 of the GNU General Public License.
-
-  "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
- 
-  "The Program" refers to any copyrightable work licensed under this
-License.  Each licensee is addressed as "you".  "Licensees" and
-"recipients" may be individuals or organizations.
-
-  To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy.  The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
-  A "covered work" means either the unmodified Program or a work based
-on the Program.
-
-  To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy.  Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
-  To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies.  Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
-  An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License.  If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
-  1. Source Code.
-
-  The "source code" for a work means the preferred form of the work
-for making modifications to it.  "Object code" means any non-source
-form of a work.
-
-  A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
-  The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form.  A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
-  The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities.  However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work.  For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
-  The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
-  The Corresponding Source for a work in source code form is that
-same work.
-
-  2. Basic Permissions.
-
-  All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met.  This License explicitly affirms your unlimited
-permission to run the unmodified Program.  The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work.  This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
-  You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force.  You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright.  Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
-  Conveying under any other circumstances is permitted solely under
-the conditions stated below.  Sublicensing is not allowed; section 10
-makes it unnecessary.
-
-  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
-  No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
-  When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
-  4. Conveying Verbatim Copies.
-
-  You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
-  You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
-  5. Conveying Modified Source Versions.
-
-  You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
-    a) The work must carry prominent notices stating that you modified
-    it, and giving a relevant date.
-
-    b) The work must carry prominent notices stating that it is
-    released under this License and any conditions added under section
-    7.  This requirement modifies the requirement in section 4 to
-    "keep intact all notices".
-
-    c) You must license the entire work, as a whole, under this
-    License to anyone who comes into possession of a copy.  This
-    License will therefore apply, along with any applicable section 7
-    additional terms, to the whole of the work, and all its parts,
-    regardless of how they are packaged.  This License gives no
-    permission to license the work in any other way, but it does not
-    invalidate such permission if you have separately received it.
-
-    d) If the work has interactive user interfaces, each must display
-    Appropriate Legal Notices; however, if the Program has interactive
-    interfaces that do not display Appropriate Legal Notices, your
-    work need not make them do so.
-
-  A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit.  Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
-  6. Conveying Non-Source Forms.
-
-  You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
-    a) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by the
-    Corresponding Source fixed on a durable physical medium
-    customarily used for software interchange.
-
-    b) Convey the object code in, or embodied in, a physical product
-    (including a physical distribution medium), accompanied by a
-    written offer, valid for at least three years and valid for as
-    long as you offer spare parts or customer support for that product
-    model, to give anyone who possesses the object code either (1) a
-    copy of the Corresponding Source for all the software in the
-    product that is covered by this License, on a durable physical
-    medium customarily used for software interchange, for a price no
-    more than your reasonable cost of physically performing this
-    conveying of source, or (2) access to copy the
-    Corresponding Source from a network server at no charge.
-
-    c) Convey individual copies of the object code with a copy of the
-    written offer to provide the Corresponding Source.  This
-    alternative is allowed only occasionally and noncommercially, and
-    only if you received the object code with such an offer, in accord
-    with subsection 6b.
-
-    d) Convey the object code by offering access from a designated
-    place (gratis or for a charge), and offer equivalent access to the
-    Corresponding Source in the same way through the same place at no
-    further charge.  You need not require recipients to copy the
-    Corresponding Source along with the object code.  If the place to
-    copy the object code is a network server, the Corresponding Source
-    may be on a different server (operated by you or a third party)
-    that supports equivalent copying facilities, provided you maintain
-    clear directions next to the object code saying where to find the
-    Corresponding Source.  Regardless of what server hosts the
-    Corresponding Source, you remain obligated to ensure that it is
-    available for as long as needed to satisfy these requirements.
-
-    e) Convey the object code using peer-to-peer transmission, provided
-    you inform other peers where the object code and Corresponding
-    Source of the work are being offered to the general public at no
-    charge under subsection 6d.
-
-  A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
-  A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling.  In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage.  For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product.  A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
-  "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source.  The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
-  If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information.  But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
-  The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed.  Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
-  Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
-  7. Additional Terms.
-
-  "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law.  If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
-  When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it.  (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.)  You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
-  Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
-    a) Disclaiming warranty or limiting liability differently from the
-    terms of sections 15 and 16 of this License; or
-
-    b) Requiring preservation of specified reasonable legal notices or
-    author attributions in that material or in the Appropriate Legal
-    Notices displayed by works containing it; or
-
-    c) Prohibiting misrepresentation of the origin of that material, or
-    requiring that modified versions of such material be marked in
-    reasonable ways as different from the original version; or
-
-    d) Limiting the use for publicity purposes of names of licensors or
-    authors of the material; or
-
-    e) Declining to grant rights under trademark law for use of some
-    trade names, trademarks, or service marks; or
-
-    f) Requiring indemnification of licensors and authors of that
-    material by anyone who conveys the material (or modified versions of
-    it) with contractual assumptions of liability to the recipient, for
-    any liability that these contractual assumptions directly impose on
-    those licensors and authors.
-
-  All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10.  If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term.  If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
-  If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
-  Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
-  8. Termination.
-
-  You may not propagate or modify a covered work except as expressly
-provided under this License.  Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
-  However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
-  Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
-  Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License.  If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
-  9. Acceptance Not Required for Having Copies.
-
-  You are not required to accept this License in order to receive or
-run a copy of the Program.  Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance.  However,
-nothing other than this License grants you permission to propagate or
-modify any covered work.  These actions infringe copyright if you do
-not accept this License.  Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
-  10. Automatic Licensing of Downstream Recipients.
-
-  Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License.  You are not responsible
-for enforcing compliance by third parties with this License.
-
-  An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations.  If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
-  You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License.  For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
-  11. Patents.
-
-  A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based.  The
-work thus licensed is called the contributor's "contributor version".
-
-  A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version.  For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
-  Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
-  In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement).  To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
-  If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients.  "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-  
-  If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
-  A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License.  You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
-  Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
-  12. No Surrender of Others' Freedom.
-
-  If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License.  If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all.  For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
-  13. Use with the GNU Affero General Public License.
-
-  Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work.  The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
-  14. Revised Versions of this License.
-
-  The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time.  Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-  Each version is given a distinguishing version number.  If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation.  If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
-  If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
-  Later license versions may give you additional or different
-permissions.  However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
-  15. Disclaimer of Warranty.
-
-  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-  16. Limitation of Liability.
-
-  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
-  17. Interpretation of Sections 15 and 16.
-
-  If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
-              END OF TERMS AND CONDITIONS
-
-     How to Apply These Terms to Your New Programs
-
-  If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
-  To do so, attach the following notices to the program.  It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-    <one line to give the program's name and a brief idea of what it does.>
-    Copyright (C) <year>  <name of author>
-
-    This program 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.
-
-    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
-  If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
-    <program>  Copyright (C) <year>  <name of author>
-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
-    This is free software, and you are welcome to redistribute it
-    under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License.  Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
-  You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
-  The GNU General Public License does not permit incorporating your program
-into proprietary programs.  If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library.  If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.  But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
+              GNU GENERAL PUBLIC LICENSE
+                Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                     Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+ 
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+              END OF TERMS AND CONDITIONS
+
+     How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program 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.
+
+    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/QuickCheck.hs b/QuickCheck.hs
new file mode 100644
--- /dev/null
+++ b/QuickCheck.hs
@@ -0,0 +1,105 @@
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE TypeSynonymInstances  #-}
+{-# LANGUAGE EmptyDataDecls        #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE OverlappingInstances  #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE PolyKinds             #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+
+module Main where
+
+import Generics.MultiRec hiding (show)
+import Generics.MultiRec.TH
+import Test.QuickCheck
+import Test.QuickCheck.Random
+import Control.Monad
+import Generics.MultiRec.Transformations.Main
+import Generics.MultiRec.Transformations.MemoTable
+import Criterion.Main
+
+data Tree = Leaf Int | Branch1 Tree Tree | Branch2 Tree Tree | Test [(Tree,Int)]
+          deriving (Show, Ord, Eq)
+
+data TreeAST :: * -> * where
+  Tree :: TreeAST Tree
+
+type instance Ixs TreeAST = '[ Tree ]
+
+data Leaf
+data Branch1
+data Branch2
+data Test
+
+instance Constructor Leaf where
+  conName _ = "Leaf"
+instance Constructor Branch1 where
+  conName _ = "Branch1"
+instance Constructor Branch2 where
+  conName _ = "Branch2"
+instance Constructor Test where
+  conName _ = "Test"
+
+type instance PF TreeAST = (C Leaf (K Int) :+: C Branch1 (I Tree :*: I Tree) :+: C Branch2 (I Tree :*: I Tree) :+: (C Test ([] :.: (I Tree :*: K Int)))) :>: Tree
+
+instance El TreeAST Tree where
+  proof = Tree
+
+instance Fam TreeAST where
+  from Tree (Leaf f0)
+    = Tag (L (C (K f0)))
+  from Tree (Branch1 f0 f1)
+    = Tag (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))
+  from Tree (Branch2 f0 f1)
+    = Tag (R (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))))
+  from Tree (Test f0)
+    = Tag (R (R (R (C (D [(I . I0) i :*: K t | (i,t) <- f0])))))
+  to Tree (Tag (L (C f0)))
+    = Leaf (unK f0)
+  to Tree (Tag (R (L (C ((:*:) f0 f1)))))
+    = Branch1 ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to Tree (Tag (R (R (L (C ((:*:) f0 f1))))))
+    = Branch2 ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to Tree (Tag (R (R (R (C (D f0))))))
+    = Test [((unI0 . unI) t, i) | t :*: K i <- f0]
+
+-- $(deriveAll ''TreeAST)
+
+-- Straight from the QC manual
+instance Arbitrary Tree where
+  shrink (Leaf v) = map Leaf (shrink v)
+  shrink (Branch1 l r) = [l,r]
+  shrink (Branch2 l r) = [l,r]
+  shrink (Test lst) = concatMap (map fst) (shrink lst)
+  arbitrary = sized tree'
+    where tree' 0 = liftM Leaf arbitrary
+          tree' n | n>0 =
+                oneof [liftM Leaf arbitrary,
+                       liftM2 Branch1 subtree subtree,
+                       liftM2 Branch2 subtree subtree,
+                       liftM Test genLst]
+            where subtree = tree' (n `div` 2)
+                  genLst  = do m <- choose (1,n)
+                               replicateM m (resize (n `div` m) arbitrary)
+
+-- Our diff property
+diffCorrect :: Tree -> Tree -> Bool
+diffCorrect a b = apply Tree a (diff Tree a b) == Just b
+
+main :: IO ()
+main = do
+  putStrLn "Generating testcases"
+  cases <- replicateM 40 (liftM2 (,) (generate arbitrary) (generate arbitrary))
+  putStrLn "Checking correctness"
+  forM_ cases $ \(a,b) -> do
+    when (not $ diffCorrect a b) $ putStrLn "Failed diffCorrect"
+  putStrLn "Benchmarking"
+  defaultMain [
+    bench "MultiRec" $ nf (map (uncurry diffCorrect)) cases
+    ]
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,24 @@
+A quick guide to the example code
+---------------------------------
+
+All the code compiles with GHC 7.10 RC2. The package itself compiles with 7.8,
+but the pattern synonyms used in the examples require 7.10.
+
+QuickCheck.hs contains an artificial benchmark for the MultiRec code.
+
+In the examples folder there are many other examples. The best way to test these
+is to load each of them in GHCi as follows:
+
+> ghci -iexamples examples\Expr.hs
+
+examples/Expr.hs
+  The Expr example shown in the paper
+
+examples/MultiRec.hs
+  The AST example shown in the paper
+
+examples/Regular.hs
+  Examples using the Regular library
+
+examples/LUA.hs
+  The Lua code example shown in the paper.
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,2 @@
-import Distribution.Simple
-main = defaultMain
+import Distribution.Simple
+main = defaultMain
diff --git a/examples/Datatypes.hs b/examples/Datatypes.hs
--- a/examples/Datatypes.hs
+++ b/examples/Datatypes.hs
@@ -1,81 +1,81 @@
-
-module Datatypes (
-  Tree (..), exTree1, exTree2, exTree3, exTree4, exTree5,
-  List (..), toL, fromL, exLst1, exLst2,
-  X (..), exX1, exX2,
-  Zig (..), Zag (..), zigzag, zigzag2,
-  Expr, prog1, prog2, prog3, prog4, prog5, prog6,
-  module Lang
-  ) where
-
-import Lang
-import Data.List ( unfoldr )
-
---------------------------------------------------------------------------------
--- Example datatypes
---------------------------------------------------------------------------------
-
---Trees
-data Tree = Leaf Int | Bin Tree Tree deriving (Show, Eq)
-
-exTree1, exTree2, exTree3, exTree4, exTree5 :: Tree
-exTree1 = Bin (Leaf 0) (Leaf 1)
-exTree2 = Bin (Leaf 1) (Leaf 0)
-exTree3 = Bin (Leaf 2) (Leaf 3)
-exTree4 = Bin exTree2 exTree3
-exTree5 = Bin exTree3 exTree4
-
--- Lists
-data List a = Nil | Cons a (List a) deriving (Eq, Show)
-
-toL :: [a] -> List a
-toL = foldr Cons Nil
-
-fromL :: List a -> [a]
-fromL = unfoldr f where
-  f Nil        = Nothing
-  f (Cons h t) = Just (h,t)
-
-exLst1, exLst2 :: List Int
-exLst1 = Cons 1 $ Cons 2 $ Cons 3 $ Cons 4 Nil
-exLst2 = Cons 4 $ Cons 2 $ Cons 3 $ Cons 1 Nil
-
--- Something more exotic
-data X = XA X | XB X | XC X X | XD Int deriving (Show, Eq)
-
-exX1, exX2 :: X
-exX1 = XA (XA (XA (XC (XD 1) (XD 2))))
-exX2 = XA (XB (XA (XA (XB (XC (XD 2) (XD 1))))))
-
--- Mutually recursive
-data Zig = Zig1 Zig | Zig2 Zag | Zig3 deriving (Show, Eq)
-data Zag = Zag1 Zag | Zag2 Zig | Zag3 deriving (Show, Eq)
-
-zigzag :: Zig
-zigzag = Zig1 (Zig2 (Zag2 Zig3))
-
-zigzag2 :: Zig
-zigzag2 = Zig2 (Zag1 (Zag2 Zig3))
-
--- Example from paper (imported from Lang)
-type Expr = AExpr
-
-progFragment1, progFragment2 :: String
-progFragment1 =     "a := 1;"
-                 ++ "b := a + 2;"
-                 ++ "if b > 3"
-                 ++ "then a := 2"
-                 ++ "else b := 1;"
-progFragment2 =     "a := 1;"
-                 ++ "b := a + 2;"
-                 ++ "if not b > 3"
-                 ++ "then b := 1"
-                 ++ "else a := 2;"
-
-prog1, prog2, prog3, prog4, prog5, prog6 :: Stmt
-prog1 = parseString . init . concat . replicate 1 $ progFragment1
-prog2 = parseString . init . concat . replicate 1 $ progFragment2
-prog3 = parseString . init . concat . replicate 4 $ progFragment1
-prog4 = parseString . init . concat . replicate 4 $ progFragment2
-prog5 = parseString . init . concat . replicate 5 $ progFragment1
-prog6 = parseString . init . concat . replicate 5 $ progFragment2
+
+module Datatypes (
+  Tree (..), exTree1, exTree2, exTree3, exTree4, exTree5,
+  List (..), toL, fromL, exLst1, exLst2,
+  X (..), exX1, exX2,
+  Zig (..), Zag (..), zigzag, zigzag2,
+  Expr, prog1, prog2, prog3, prog4, prog5, prog6,
+  module Lang
+  ) where
+
+import Lang
+import Data.List ( unfoldr )
+
+--------------------------------------------------------------------------------
+-- Example datatypes
+--------------------------------------------------------------------------------
+
+--Trees
+data Tree = Leaf Int | Bin Tree Tree deriving (Show, Eq)
+
+exTree1, exTree2, exTree3, exTree4, exTree5 :: Tree
+exTree1 = Bin (Leaf 0) (Leaf 1)
+exTree2 = Bin (Leaf 1) (Leaf 0)
+exTree3 = Bin (Leaf 2) (Leaf 3)
+exTree4 = Bin exTree2 exTree3
+exTree5 = Bin exTree3 exTree4
+
+-- Lists
+data List a = Nil | Cons a (List a) deriving (Eq, Show)
+
+toL :: [a] -> List a
+toL = foldr Cons Nil
+
+fromL :: List a -> [a]
+fromL = unfoldr f where
+  f Nil        = Nothing
+  f (Cons h t) = Just (h,t)
+
+exLst1, exLst2 :: List Int
+exLst1 = Cons 1 $ Cons 2 $ Cons 3 $ Cons 4 Nil
+exLst2 = Cons 4 $ Cons 2 $ Cons 3 $ Cons 1 Nil
+
+-- Something more exotic
+data X = XA X | XB X | XC X X | XD Int deriving (Show, Eq)
+
+exX1, exX2 :: X
+exX1 = XA (XA (XA (XC (XD 1) (XD 2))))
+exX2 = XA (XB (XA (XA (XB (XC (XD 2) (XD 1))))))
+
+-- Mutually recursive
+data Zig = Zig1 Zig | Zig2 Zag | Zig3 deriving (Show, Eq)
+data Zag = Zag1 Zag | Zag2 Zig | Zag3 deriving (Show, Eq)
+
+zigzag :: Zig
+zigzag = Zig1 (Zig2 (Zag2 Zig3))
+
+zigzag2 :: Zig
+zigzag2 = Zig2 (Zag1 (Zag2 Zig3))
+
+-- Example from paper (imported from Lang)
+type Expr = AExpr
+
+progFragment1, progFragment2 :: String
+progFragment1 =     "a := 1;"
+                 ++ "b := a + 2;"
+                 ++ "if b > 3"
+                 ++ "then a := 2"
+                 ++ "else b := 1;"
+progFragment2 =     "a := 1;"
+                 ++ "b := a + 2;"
+                 ++ "if not b > 3"
+                 ++ "then b := 1"
+                 ++ "else a := 2;"
+
+prog1, prog2, prog3, prog4, prog5, prog6 :: Stmt
+prog1 = parseString . init . concat . replicate 1 $ progFragment1
+prog2 = parseString . init . concat . replicate 1 $ progFragment2
+prog3 = parseString . init . concat . replicate 4 $ progFragment1
+prog4 = parseString . init . concat . replicate 4 $ progFragment2
+prog5 = parseString . init . concat . replicate 5 $ progFragment1
+prog6 = parseString . init . concat . replicate 5 $ progFragment2
diff --git a/examples/Expr.hs b/examples/Expr.hs
new file mode 100644
--- /dev/null
+++ b/examples/Expr.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE TypeSynonymInstances  #-}
+{-# LANGUAGE EmptyDataDecls        #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE OverlappingInstances  #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE PolyKinds             #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+{-# LANGUAGE PatternSynonyms       #-}
+
+module Main where
+
+import Generics.MultiRec hiding (show)
+import Generics.MultiRec.TH
+import Test.QuickCheck
+import Test.QuickCheck.Random
+import Control.Monad
+import Generics.MultiRec.Transformations.Main
+import Generics.MultiRec.Transformations.MemoTable
+
+data Expr  =  Var    String
+           |  Const  Int
+           |  Neg    Expr
+           |  Add    Expr Expr
+          deriving (Show, Ord, Eq)
+
+data ExprAST :: * -> * where
+  Expr :: ExprAST Expr
+
+type instance Ixs ExprAST = '[ Expr ]
+
+$(deriveAll ''ExprAST)
+
+instance Arbitrary Expr where
+  shrink (Var v)   = map Var   (shrink v)
+  shrink (Const v) = map Const (shrink v)
+  shrink (Neg l)   = [l]
+  shrink (Add l r) = [l,r]
+
+  arbitrary = sized expr'
+    where expr' 0 = oneof [liftM Var arbitrary, liftM Const arbitrary]
+          expr' n | n>0 =
+                oneof [ liftM Var arbitrary
+                      , liftM Const arbitrary
+                      , liftM Neg (expr' (pred n))
+                      , liftM2 Add subtree subtree ]
+            where subtree = expr' (n `div` 2)
+
+expr1, expr2, expr3 :: Expr
+expr1  =  Add (Const 1) (Var "a")
+expr2  =  Add (Const 1) (Neg (Var "a"))
+expr3  =  Add (Var "a") (Const 1)
diff --git a/examples/LUA.hs b/examples/LUA.hs
new file mode 100644
--- /dev/null
+++ b/examples/LUA.hs
@@ -0,0 +1,715 @@
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+{-# LANGUAGE CPP                   #-}
+
+import Control.Monad
+import qualified Language.Lua as LUA -- from language-lua
+import Generics.MultiRec hiding (show)
+import Generics.MultiRec.Transformations.Main
+
+-- From https://github.com/leafo/lapis/commits/629c559094df41694bea0a33a2be75115c544dad/lapis/application.lua
+files :: [FilePath]
+files = ["examples/LUA_project/" ++ f
+        | f <- [ "application.lua." ++ show n | n <- [1..90] ] ]
+
+--------------------------------------------------------------------------------
+-- Main
+--------------------------------------------------------------------------------
+main :: IO ()
+main = do
+  putStrLn "Parsing"
+  psr <- forM files $ LUA.parseFile
+  let ps = [ (p,f) | (Right p,f) <- zip psr files ]
+  putStrLn "Diffing"
+  forM_ (zip ps (tail ps)) $ \((p1,f1),(p2,f2)) -> do
+    putStrLn $ f1 ++ " --> " ++ f2
+    let df = diff Block p1 p2
+    print $ length df
+    print $ apply Block p1 df == Just p2
+
+--------------------------------------------------------------------------------
+-- Multirec instance
+--------------------------------------------------------------------------------
+data AST :: * -> * where
+  Stat :: AST LUA.Stat
+  Exp :: AST LUA.Exp
+  Var :: AST LUA.Var
+  Binop :: AST LUA.Binop
+  Unop :: AST LUA.Unop
+  PrefixExp :: AST LUA.PrefixExp
+  TableField :: AST LUA.TableField
+  Block :: AST LUA.Block
+  FunName :: AST LUA.FunName
+  FunBody :: AST LUA.FunBody
+  FunCall :: AST LUA.FunCall
+  FunArg :: AST LUA.FunArg
+
+deriving instance Ord LUA.Stat
+deriving instance Ord LUA.Exp
+deriving instance Ord LUA.Var
+deriving instance Ord LUA.Binop
+deriving instance Ord LUA.Unop
+deriving instance Ord LUA.PrefixExp
+deriving instance Ord LUA.TableField
+deriving instance Ord LUA.Block
+deriving instance Ord LUA.FunName
+deriving instance Ord LUA.FunBody
+deriving instance Ord LUA.FunCall
+deriving instance Ord LUA.FunArg
+
+
+#if OLD_APPROACH
+instance Transform AST
+
+instance OrdI AST where
+  indexI Stat = 0
+  indexI Exp = 1
+  indexI Var = 2
+  indexI Binop = 3
+  indexI Unop = 4
+  indexI PrefixExp = 5
+  indexI TableField = 6
+  indexI Block = 7
+  indexI FunName = 8
+  indexI FunBody = 9
+  indexI FunCall = 10
+  indexI FunArg = 11
+#else
+type instance Ixs AST = '[ LUA.Stat, LUA.Exp, LUA.Var, LUA.Binop, LUA.Unop, LUA.PrefixExp, LUA.TableField, LUA.Block, LUA.FunName, LUA.FunBody, LUA.FunCall, LUA.FunArg ]
+#endif
+
+-- Automatically generated and manually edited
+data Assign
+data FunCall
+data Label
+data Break
+data Goto
+data Do
+data While
+data Repeat
+data If
+data ForRange
+data ForIn
+data FunAssign
+data LocalFunAssign
+data LocalAssign
+data EmptyStat
+instance Constructor Assign where
+  conName _ = "Assign"
+instance Constructor FunCall where
+  conName _ = "FunCall"
+instance Constructor Label where
+  conName _ = "Label"
+instance Constructor Break where
+  conName _ = "Break"
+instance Constructor Goto where
+  conName _ = "Goto"
+instance Constructor Do where
+  conName _ = "Do"
+instance Constructor While where
+  conName _ = "While"
+instance Constructor Repeat where
+  conName _ = "Repeat"
+instance Constructor If where
+  conName _ = "If"
+instance Constructor ForRange where
+  conName _ = "ForRange"
+instance Constructor ForIn where
+  conName _ = "ForIn"
+instance Constructor FunAssign where
+  conName _ = "FunAssign"
+instance Constructor LocalFunAssign where
+  conName _ = "LocalFunAssign"
+instance Constructor LocalAssign where
+  conName _ = "LocalAssign"
+instance Constructor EmptyStat where
+  conName _ = "EmptyStat"
+data Nil
+data LBool
+data Number
+data LString
+data Vararg
+data EFunDef
+data PrefixExp
+data TableConst
+data Binop
+data Unop
+instance Constructor Nil where
+  conName _ = "Nil"
+instance Constructor LBool where
+  conName _ = "Bool"
+instance Constructor Number where
+  conName _ = "Number"
+instance Constructor LString where
+  conName _ = "String"
+instance Constructor Vararg where
+  conName _ = "Vararg"
+instance Constructor EFunDef where
+  conName _ = "EFunDef"
+instance Constructor PrefixExp where
+  conName _ = "PrefixExp"
+instance Constructor TableConst where
+  conName _ = "TableConst"
+instance Constructor Binop where
+  conName _ = "Binop"
+instance Constructor Unop where
+  conName _ = "Unop"
+data VarName
+data Select
+data SelectName
+instance Constructor VarName where
+  conName _ = "VarName"
+instance Constructor Select where
+  conName _ = "Select"
+instance Constructor SelectName where
+  conName _ = "SelectName"
+data Add
+data Sub
+data Mul
+data Div
+data Exp
+data Mod
+data Concat
+data LT
+data LTE
+data GT
+data GTE
+data EQ
+data NEQ
+data And
+data Or
+instance Constructor Add where
+  conName _ = "Add"
+instance Constructor Sub where
+  conName _ = "Sub"
+instance Constructor Mul where
+  conName _ = "Mul"
+instance Constructor Div where
+  conName _ = "Div"
+instance Constructor Exp where
+  conName _ = "Exp"
+instance Constructor Mod where
+  conName _ = "Mod"
+instance Constructor Concat where
+  conName _ = "Concat"
+instance Constructor LT where
+  conName _ = "LT"
+instance Constructor LTE where
+  conName _ = "LTE"
+instance Constructor GT where
+  conName _ = "GT"
+instance Constructor GTE where
+  conName _ = "GTE"
+instance Constructor EQ where
+  conName _ = "EQ"
+instance Constructor NEQ where
+  conName _ = "NEQ"
+instance Constructor And where
+  conName _ = "And"
+instance Constructor Or where
+  conName _ = "Or"
+data Neg
+data Not
+data Len
+instance Constructor Neg where
+  conName _ = "Neg"
+instance Constructor Not where
+  conName _ = "Not"
+instance Constructor Len where
+  conName _ = "Len"
+data PEVar
+data PEFunCall
+data Paren
+instance Constructor PEVar where
+  conName _ = "PEVar"
+instance Constructor PEFunCall where
+  conName _ = "PEFunCall"
+instance Constructor Paren where
+  conName _ = "Paren"
+data ExpField
+data NamedField
+data Field
+instance Constructor ExpField where
+  conName _ = "ExpField"
+instance Constructor NamedField where
+  conName _ = "NamedField"
+instance Constructor Field where
+  conName _ = "Field"
+data Block
+instance Constructor Block where
+  conName _ = "Block"
+data FunName
+instance Constructor FunName where
+  conName _ = "FunName"
+data FunBody
+instance Constructor FunBody where
+  conName _ = "FunBody"
+data NormalFunCall
+data MethodCall
+instance Constructor NormalFunCall where
+  conName _ = "NormalFunCall"
+instance Constructor MethodCall where
+  conName _ = "MethodCall"
+data Args
+data TableArg
+data StringArg
+instance Constructor Args where
+  conName _ = "Args"
+instance Constructor TableArg where
+  conName _ = "TableArg"
+instance Constructor StringArg where
+  conName _ = "StringArg"
+
+type instance PF AST = (:+:) ((:>:)
+  ((:+:) (C Assign ((:*:) ((:.:) [] (I LUA.Var)) ((:.:) [] (I LUA.Exp))))
+  ((:+:) (C FunCall (I LUA.FunCall))
+  ((:+:) (C Label (K LUA.Name))
+  ((:+:) (C Break U)
+  ((:+:) (C Goto (K LUA.Name))
+  ((:+:) (C Do (I LUA.Block))
+  ((:+:) (C While ((:*:) (I LUA.Exp) (I LUA.Block)))
+  ((:+:) (C Repeat ((:*:) (I LUA.Block) (I LUA.Exp)))
+  ((:+:) (C If ((:*:) ((:.:) [] ((:*:) (I LUA.Exp) (I LUA.Block))) ((:.:) Maybe (I LUA.Block)))) -- Manually changed, is it correct?
+  ((:+:) (C ForRange ((:*:) (K LUA.Name) ((:*:) (I LUA.Exp) ((:*:) (I LUA.Exp) ((:*:) ((:.:) Maybe (I LUA.Exp)) (I LUA.Block))))))
+  ((:+:) (C ForIn ((:*:) ((:.:) [] (K LUA.Name)) ((:*:) ((:.:) [] (I LUA.Exp)) (I LUA.Block))))
+  ((:+:) (C FunAssign ((:*:) (I LUA.FunName) (I LUA.FunBody)))
+  ((:+:) (C LocalFunAssign ((:*:) (K LUA.Name) (I LUA.FunBody)))
+  ((:+:) (C LocalAssign ((:*:) ((:.:) [] (K LUA.Name)) ((:.:) Maybe ((:.:) [] (I LUA.Exp)))))
+   (C EmptyStat U))))))))))))))) LUA.Stat) ((:+:) ((:>:)
+  ((:+:) (C Nil U)
+  ((:+:) (C LBool (K Bool))
+  ((:+:) (C Number (K String))
+  ((:+:) (C LString (K String))
+  ((:+:) (C Vararg U)
+  ((:+:) (C EFunDef (I LUA.FunBody))
+  ((:+:) (C PrefixExp (I LUA.PrefixExp))
+  ((:+:) (C TableConst ((:.:) [] (I LUA.TableField)))
+  ((:+:) (C Binop ((:*:) (I LUA.Binop) ((:*:) (I LUA.Exp) (I LUA.Exp))))
+   (C Unop ((:*:) (I LUA.Unop) (I LUA.Exp)))))))))))) LUA.Exp) ((:+:) ((:>:)
+  ((:+:) (C VarName (K LUA.Name))
+  ((:+:) (C Select ((:*:) (I LUA.PrefixExp) (I LUA.Exp))) (C SelectName ((:*:) (I LUA.PrefixExp) (K LUA.Name))))) LUA.Var) ((:+:) ((:>:)
+  ((:+:) (C Add U)
+  ((:+:) (C Sub U)
+  ((:+:) (C Mul U)
+  ((:+:) (C Div U)
+  ((:+:) (C Exp U)
+  ((:+:) (C Mod U)
+  ((:+:) (C Concat U)
+  ((:+:) (C LT U)
+  ((:+:) (C LTE U)
+  ((:+:) (C GT U)
+  ((:+:) (C GTE U)
+  ((:+:) (C EQ U)
+  ((:+:) (C NEQ U)
+  ((:+:) (C And U) (C Or U))))))))))))))) LUA.Binop)
+  ((:+:) ((:>:)
+  ((:+:) (C Neg U)
+  ((:+:) (C Not U) (C Len U))) LUA.Unop)
+  ((:+:) ((:>:)
+  ((:+:) (C PEVar (I LUA.Var))
+  ((:+:) (C PEFunCall (I LUA.FunCall)) (C Paren (I LUA.Exp)))) LUA.PrefixExp)
+  ((:+:) ((:>:)
+  ((:+:) (C ExpField ((:*:) (I LUA.Exp) (I LUA.Exp)))
+  ((:+:) (C NamedField ((:*:) (K LUA.Name) (I LUA.Exp))) (C Field (I LUA.Exp)))) LUA.TableField)
+  ((:+:) ((:>:) (C Block ((:*:) ((:.:) [] (I LUA.Stat)) ((:.:) Maybe ((:.:) [] (I LUA.Exp))))) LUA.Block)
+  ((:+:) ((:>:) (C FunName ((:*:) (K LUA.Name) ((:*:) ((:.:) [] (K LUA.Name)) ((:.:) Maybe (K LUA.Name))))) LUA.FunName)
+  ((:+:) ((:>:) (C FunBody ((:*:) ((:.:) [] (K LUA.Name)) ((:*:) (K Bool) (I LUA.Block)))) LUA.FunBody)
+  ((:+:) ((:>:)
+  ((:+:) (C NormalFunCall ((:*:) (I LUA.PrefixExp) (I LUA.FunArg))) (C MethodCall ((:*:) (I LUA.PrefixExp) ((:*:) (K LUA.Name) (I LUA.FunArg))))) LUA.FunCall) ((:>:)
+  ((:+:) (C Args ((:.:) [] (I LUA.Exp)))
+  ((:+:) (C TableArg ((:.:) [] (I LUA.TableField))) (C StringArg (K String)))) LUA.FunArg)))))))))))
+
+instance El AST LUA.Stat where
+  proof = Stat
+instance El AST LUA.Exp where
+  proof = Exp
+instance El AST LUA.Var where
+  proof = Var
+instance El AST LUA.Binop where
+  proof = Binop
+instance El AST LUA.Unop where
+  proof = Unop
+instance El AST LUA.PrefixExp where
+  proof = PrefixExp
+instance El AST LUA.TableField where
+  proof = TableField
+instance El AST LUA.Block where
+  proof = Block
+instance El AST LUA.FunName where
+  proof = FunName
+instance El AST LUA.FunBody where
+  proof = FunBody
+instance El AST LUA.FunCall where
+  proof = FunCall
+instance El AST LUA.FunArg where
+  proof = FunArg
+instance Fam AST where
+  from Stat (LUA.Assign f0 f1)
+    = L (Tag
+           (L (C ((:*:)
+                    ((D . (fmap (I . I0))) f0) ((D . (fmap (I . I0))) f1)))))
+  from Stat (LUA.FunCall f0)
+    = L (Tag (R (L (C ((I . I0) f0)))))
+  from Stat (LUA.Label f0) = L (Tag (R (R (L (C (K f0))))))
+  from Stat LUA.Break = L (Tag (R (R (R (L (C U))))))
+  from Stat (LUA.Goto f0) = L (Tag (R (R (R (R (L (C (K f0))))))))
+  from Stat (LUA.Do f0)
+    = L (Tag (R (R (R (R (R (L (C ((I . I0) f0)))))))))
+  from Stat (LUA.While f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (L (C ((:*:)
+                                      ((I . I0) f0) ((I . I0) f1)))))))))))
+  from Stat (LUA.Repeat f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (R (L (C ((:*:)
+                                         ((I . I0) f0) ((I . I0) f1))))))))))))
+  from Stat (LUA.If f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                            (D [((I . I0) e :*: (I . I0) b) | (e, b) <- f0])
+                                            ((D . (fmap (I . I0))) f1)))))))))))))
+  from Stat (LUA.ForRange f0 f1 f2 f3 f4)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                               (K f0)
+                                               ((:*:)
+                                                  ((I . I0) f1)
+                                                  ((:*:)
+                                                     ((I . I0) f2)
+                                                     ((:*:)
+                                                        ((D . (fmap (I . I0))) f3)
+                                                        ((I . I0) f4)))))))))))))))))
+  from Stat (LUA.ForIn f0 f1 f2)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                                  ((D . (fmap K)) f0)
+                                                  ((:*:)
+                                                     ((D . (fmap (I . I0))) f1)
+                                                     ((I . I0) f2))))))))))))))))
+  from Stat (LUA.FunAssign f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                                     ((I . I0) f0) ((I . I0) f1))))))))))))))))
+  from Stat (LUA.LocalFunAssign f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                                        (K f0) ((I . I0) f1)))))))))))))))))
+  from Stat (LUA.LocalAssign f0 f1)
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                                           ((D . (fmap K)) f0)
+                                                           ((D . (fmap (D . (fmap (I . I0)))))
+                                                              f1))))))))))))))))))
+  from Stat LUA.EmptyStat
+    = L (Tag
+           (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U))))))))))))))))
+  from Exp LUA.Nil = R (L (Tag (L (C U))))
+  from Exp (LUA.Bool f0) = R (L (Tag (R (L (C (K f0))))))
+  from Exp (LUA.Number f0) = R (L (Tag (R (R (L (C (K f0)))))))
+  from Exp (LUA.String f0) = R (L (Tag (R (R (R (L (C (K f0))))))))
+  from Exp LUA.Vararg = R (L (Tag (R (R (R (R (L (C U))))))))
+  from Exp (LUA.EFunDef f0)
+    = R (L (Tag (R (R (R (R (R (L (C ((I . I0) f0))))))))))
+  from Exp (LUA.PrefixExp f0)
+    = R (L (Tag (R (R (R (R (R (R (L (C ((I . I0) f0)))))))))))
+  from Exp (LUA.TableConst f0)
+    = R (L (Tag
+              (R (R (R (R (R (R (R (L (C ((D . (fmap (I . I0))) f0))))))))))))
+  from Exp (LUA.Binop f0 f1 f2)
+    = R (L (Tag
+              (R (R (R (R (R (R (R (R (L (C ((:*:)
+                                               ((I . I0) f0)
+                                               ((:*:) ((I . I0) f1) ((I . I0) f2)))))))))))))))
+  from Exp (LUA.Unop f0 f1)
+    = R (L (Tag
+              (R (R (R (R (R (R (R (R (R (C ((:*:)
+                                               ((I . I0) f0) ((I . I0) f1))))))))))))))
+  from Var (LUA.VarName f0) = R (R (L (Tag (L (C (K f0))))))
+  from Var (LUA.Select f0 f1)
+    = R (R (L (Tag (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))))))
+  from Var (LUA.SelectName f0 f1)
+    = R (R (L (Tag (R (R (C ((:*:) ((I . I0) f0) (K f1))))))))
+  from Binop LUA.Add = R (R (R (L (Tag (L (C U))))))
+  from Binop LUA.Sub = R (R (R (L (Tag (R (L (C U)))))))
+  from Binop LUA.Mul = R (R (R (L (Tag (R (R (L (C U))))))))
+  from Binop LUA.Div = R (R (R (L (Tag (R (R (R (L (C U)))))))))
+  from Binop LUA.Exp
+    = R (R (R (L (Tag (R (R (R (R (L (C U))))))))))
+  from Binop LUA.Mod = R (R (R (L (Tag (R (R (R (R (R (L (C U)))))))))))
+  from Binop LUA.Concat
+    = R (R (R (L (Tag (R (R (R (R (R (R (L (C U))))))))))))
+  from Binop LUA.LT
+    = R (R (R (L (Tag (R (R (R (R (R (R (R (L (C U)))))))))))))
+  from Binop LUA.LTE
+    = R (R (R (L (Tag (R (R (R (R (R (R (R (R (L (C U))))))))))))))
+  from Binop LUA.GT
+    = R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))
+  from Binop LUA.GTE
+    = R (R (R (L (Tag
+                    (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))
+  from Binop LUA.EQ
+    = R (R (R (L (Tag
+                    (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))
+  from Binop LUA.NEQ
+    = R (R (R (L (Tag
+                    (R (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))))
+  from Binop LUA.And
+    = R (R (R (L (Tag
+                    (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))))
+  from Binop LUA.Or
+    = R (R (R (L (Tag
+                    (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U)))))))))))))))))))
+  from Unop LUA.Neg = R (R (R (R (L (Tag (L (C U)))))))
+  from Unop LUA.Not = R (R (R (R (L (Tag (R (L (C U))))))))
+  from Unop LUA.Len = R (R (R (R (L (Tag (R (R (C U))))))))
+  from PrefixExp (LUA.PEVar f0)
+    = R (R (R (R (R (L (Tag (L (C ((I . I0) f0)))))))))
+  from PrefixExp (LUA.PEFunCall f0)
+    = R (R (R (R (R (L (Tag (R (L (C ((I . I0) f0))))))))))
+  from PrefixExp (LUA.Paren f0)
+    = R (R (R (R (R (L (Tag (R (R (C ((I . I0) f0))))))))))
+  from TableField (LUA.ExpField f0 f1)
+    = R (R (R (R (R (R (L (Tag
+                             (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))))))))
+  from TableField (LUA.NamedField f0 f1)
+    = R (R (R (R (R (R (L (Tag
+                             (R (L (C ((:*:) (K f0) ((I . I0) f1))))))))))))
+  from TableField (LUA.Field f0)
+    = R (R (R (R (R (R (L (Tag (R (R (C ((I . I0) f0)))))))))))
+  from Block (LUA.Block f0 f1)
+    = R (R (R (R (R (R (R (L (Tag
+                                (C ((:*:)
+                                      ((D . (fmap (I . I0))) f0)
+                                      ((D . (fmap (D . (fmap (I . I0))))) f1)))))))))))
+  from FunName (LUA.FunName f0 f1 f2)
+    = R (R (R (R (R (R (R (R (L (Tag
+                                   (C ((:*:)
+                                         (K f0)
+                                         ((:*:)
+                                            ((D . (fmap K)) f1) ((D . (fmap K)) f2)))))))))))))
+  from FunBody (LUA.FunBody f0 f1 f2)
+    = R (R (R (R (R (R (R (R (R (L (Tag
+                                      (C ((:*:)
+                                            ((D . (fmap K)) f0)
+                                            ((:*:) (K f1) ((I . I0) f2))))))))))))))
+  from FunCall (LUA.NormalFunCall f0 f1)
+    = R (R (R (R (R (R (R (R (R (R (L (Tag
+                                         (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))))))))))))
+  from FunCall (LUA.MethodCall f0 f1 f2)
+    = R (R (R (R (R (R (R (R (R (R (L (Tag
+                                         (R (C ((:*:)
+                                                  ((I . I0) f0)
+                                                  ((:*:) (K f1) ((I . I0) f2))))))))))))))))
+  from FunArg (LUA.Args f0)
+    = R (R (R (R (R (R (R (R (R (R (R (Tag
+                                         (L (C ((D . (fmap (I . I0))) f0))))))))))))))
+  from FunArg (LUA.TableArg f0)
+    = R (R (R (R (R (R (R (R (R (R (R (Tag
+                                         (R (L (C ((D . (fmap (I . I0))) f0)))))))))))))))
+  from FunArg (LUA.StringArg f0)
+    = R (R (R (R (R (R (R (R (R (R (R (Tag
+                                         (R (R (C (K f0)))))))))))))))
+  to Stat (L (Tag (L (C ((:*:) f0 f1)))))
+    = LUA.Assign
+        (((fmap (unI0 . unI)) . unD) f0) (((fmap (unI0 . unI)) . unD) f1)
+  to Stat (L (Tag (R (L (C f0)))))
+    = LUA.FunCall ((unI0 . unI) f0)
+  to Stat (L (Tag (R (R (L (C f0)))))) = LUA.Label (unK f0)
+  to Stat (L (Tag (R (R (R (L (C U))))))) = LUA.Break
+  to Stat (L (Tag (R (R (R (R (L (C f0)))))))) = LUA.Goto (unK f0)
+  to Stat (L (Tag (R (R (R (R (R (L (C f0)))))))))
+    = LUA.Do ((unI0 . unI) f0)
+  to Stat (L (Tag (R (R (R (R (R (R (L (C ((:*:) f0 f1)))))))))))
+    = LUA.While ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to Stat (L (Tag (R (R (R (R (R (R (R (L (C ((:*:) f0 f1))))))))))))
+    = LUA.Repeat ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (L (C ((:*:) f0 f1)))))))))))))
+    = LUA.If
+        [((unI0 . unI) e, (unI0 . unI) b)  | (e :*: b) <- unD f0]
+        (((fmap (unI0 . unI)) . unD) f1)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                    ((:*:) f1
+                                                           ((:*:) f2
+                                                                  ((:*:) f3 f4)))))))))))))))))
+    = LUA.ForRange
+        (unK f0)
+        ((unI0 . unI) f1)
+        ((unI0 . unI) f2)
+        (((fmap (unI0 . unI)) . unD) f3)
+        ((unI0 . unI) f4)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                       ((:*:) f1 f2))))))))))))))))
+    = LUA.ForIn
+        (((fmap unK) . unD) f0)
+        (((fmap (unI0 . unI)) . unD) f1)
+        ((unI0 . unI) f2)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                          f1))))))))))))))))
+    = LUA.FunAssign ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                             f1)))))))))))))))))
+    = LUA.LocalFunAssign (unK f0) ((unI0 . unI) f1)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                                f1))))))))))))))))))
+    = LUA.LocalAssign
+        (((fmap unK) . unD) f0)
+        (((fmap ((fmap (unI0 . unI)) . unD)) . unD) f1)
+  to
+    Stat
+    (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U)))))))))))))))))
+    = LUA.EmptyStat
+  to Exp (R (L (Tag (L (C U))))) = LUA.Nil
+  to Exp (R (L (Tag (R (L (C f0)))))) = LUA.Bool (unK f0)
+  to Exp (R (L (Tag (R (R (L (C f0))))))) = LUA.Number (unK f0)
+  to Exp (R (L (Tag (R (R (R (L (C f0)))))))) = LUA.String (unK f0)
+  to Exp (R (L (Tag (R (R (R (R (L (C U))))))))) = LUA.Vararg
+  to Exp (R (L (Tag (R (R (R (R (R (L (C f0))))))))))
+    = LUA.EFunDef ((unI0 . unI) f0)
+  to Exp (R (L (Tag (R (R (R (R (R (R (L (C f0)))))))))))
+    = LUA.PrefixExp ((unI0 . unI) f0)
+  to Exp (R (L (Tag (R (R (R (R (R (R (R (L (C f0))))))))))))
+    = LUA.TableConst (((fmap (unI0 . unI)) . unD) f0)
+  to
+    Exp
+    (R (L (Tag (R (R (R (R (R (R (R (R (L (C ((:*:) f0
+                                                    ((:*:) f1 f2)))))))))))))))
+    = LUA.Binop
+        ((unI0 . unI) f0) ((unI0 . unI) f1) ((unI0 . unI) f2)
+  to
+    Exp
+    (R (L (Tag (R (R (R (R (R (R (R (R (R (C ((:*:) f0 f1))))))))))))))
+    = LUA.Unop ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to Var (R (R (L (Tag (L (C f0)))))) = LUA.VarName (unK f0)
+  to Var (R (R (L (Tag (R (L (C ((:*:) f0 f1))))))))
+    = LUA.Select ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to Var (R (R (L (Tag (R (R (C ((:*:) f0 f1))))))))
+    = LUA.SelectName ((unI0 . unI) f0) (unK f1)
+  to Binop (R (R (R (L (Tag (L (C U))))))) = LUA.Add
+  to Binop (R (R (R (L (Tag (R (L (C U)))))))) = LUA.Sub
+  to Binop (R (R (R (L (Tag (R (R (L (C U))))))))) = LUA.Mul
+  to Binop (R (R (R (L (Tag (R (R (R (L (C U)))))))))) = LUA.Div
+  to Binop (R (R (R (L (Tag (R (R (R (R (L (C U)))))))))))
+    = LUA.Exp
+  to Binop (R (R (R (L (Tag (R (R (R (R (R (L (C U)))))))))))) = LUA.Mod
+  to Binop (R (R (R (L (Tag (R (R (R (R (R (R (L (C U)))))))))))))
+    = LUA.Concat
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (L (C U))))))))))))))
+    = LUA.LT
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (L (C U)))))))))))))))
+    = LUA.LTE
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))
+    = LUA.GT
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))
+    = LUA.GTE
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))))
+    = LUA.EQ
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))))
+    = LUA.NEQ
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))))))
+    = LUA.And
+  to
+    Binop
+    (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U))))))))))))))))))))
+    = LUA.Or
+  to Unop (R (R (R (R (L (Tag (L (C U)))))))) = LUA.Neg
+  to Unop (R (R (R (R (L (Tag (R (L (C U))))))))) = LUA.Not
+  to Unop (R (R (R (R (L (Tag (R (R (C U))))))))) = LUA.Len
+  to PrefixExp (R (R (R (R (R (L (Tag (L (C f0)))))))))
+    = LUA.PEVar ((unI0 . unI) f0)
+  to PrefixExp (R (R (R (R (R (L (Tag (R (L (C f0))))))))))
+    = LUA.PEFunCall ((unI0 . unI) f0)
+  to PrefixExp (R (R (R (R (R (L (Tag (R (R (C f0))))))))))
+    = LUA.Paren ((unI0 . unI) f0)
+  to
+    TableField
+    (R (R (R (R (R (R (L (Tag (L (C ((:*:) f0 f1)))))))))))
+    = LUA.ExpField ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to
+    TableField
+    (R (R (R (R (R (R (L (Tag (R (L (C ((:*:) f0 f1))))))))))))
+    = LUA.NamedField (unK f0) ((unI0 . unI) f1)
+  to TableField (R (R (R (R (R (R (L (Tag (R (R (C f0)))))))))))
+    = LUA.Field ((unI0 . unI) f0)
+  to Block (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0 f1)))))))))))
+    = LUA.Block
+        (((fmap (unI0 . unI)) . unD) f0)
+        (((fmap ((fmap (unI0 . unI)) . unD)) . unD) f1)
+  to
+    FunName
+    (R (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0
+                                              ((:*:) f1 f2)))))))))))))
+    = LUA.FunName
+        (unK f0) (((fmap unK) . unD) f1) (((fmap unK) . unD) f2)
+  to
+    FunBody
+    (R (R (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0
+                                                 ((:*:) f1 f2))))))))))))))
+    = LUA.FunBody
+        (((fmap unK) . unD) f0) (unK f1) ((unI0 . unI) f2)
+  to
+    FunCall
+    (R (R (R (R (R (R (R (R (R (R (L (Tag (L (C ((:*:) f0
+                                                       f1)))))))))))))))
+    = LUA.NormalFunCall ((unI0 . unI) f0) ((unI0 . unI) f1)
+  to
+    FunCall
+    (R (R (R (R (R (R (R (R (R (R (L (Tag (R (C ((:*:) f0
+                                                       ((:*:) f1 f2))))))))))))))))
+    = LUA.MethodCall ((unI0 . unI) f0) (unK f1) ((unI0 . unI) f2)
+  to
+    FunArg
+    (R (R (R (R (R (R (R (R (R (R (R (Tag (L (C f0))))))))))))))
+    = LUA.Args (((fmap (unI0 . unI)) . unD) f0)
+  to
+    FunArg
+    (R (R (R (R (R (R (R (R (R (R (R (Tag (R (L (C f0)))))))))))))))
+    = LUA.TableArg (((fmap (unI0 . unI)) . unD) f0)
+  to
+    FunArg
+    (R (R (R (R (R (R (R (R (R (R (R (Tag (R (R (C f0)))))))))))))))
+    = LUA.StringArg (unK f0)
+
+instance EqS AST where
+  eqS Stat Stat = Just Refl
+  eqS Exp Exp = Just Refl
+  eqS Var Var = Just Refl
+  eqS Binop Binop = Just Refl
+  eqS Unop Unop = Just Refl
+  eqS PrefixExp PrefixExp = Just Refl
+  eqS TableField TableField = Just Refl
+  eqS Block Block = Just Refl
+  eqS FunName FunName = Just Refl
+  eqS FunBody FunBody = Just Refl
+  eqS FunCall FunCall = Just Refl
+  eqS FunArg FunArg = Just Refl
+  eqS _ _ = Nothing
diff --git a/examples/LUA_project/application.lua.1 b/examples/LUA_project/application.lua.1
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.1
@@ -0,0 +1,733 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local lapis_config = require("lapis.config")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local increment_perf
+do
+  local _obj_0 = require("lapis.nginx.context")
+  increment_perf = _obj_0.increment_perf
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      local config = lapis_config.get()
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local start_time
+        if config.measure_performance then
+          ngx.update_time()
+          start_time = ngx.now()
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+        if start_time then
+          ngx.update_time()
+          increment_perf("view_time", ngx.now() - start_time)
+        end
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local start_time
+        if config.measure_performance then
+          ngx.update_time()
+          start_time = ngx.now()
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+        if start_time then
+          ngx.update_time()
+          increment_perf("layout_time", ngx.now() - start_time)
+        end
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+        do
+          local extra = self.app.cookie_attributes(self, k, v)
+          if extra then
+            cookie = cookie .. ("; " .. extra)
+          end
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      local config = lapis_config.get()
+      if config._name == "test" then
+        local param_dump = logger.flatten_params(self.url_params)
+        r.res:add_header("X-Lapis-Error", "true")
+        r:write({
+          status = 500,
+          json = {
+            status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump),
+            err = err,
+            trace = trace
+          }
+        })
+      else
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          error_page({
+            status = 500,
+            err = err,
+            trace = trace
+          })
+        })
+      end
+      r:render()
+      logger.request(r)
+      return r
+    end,
+    cookie_attributes = function(self, name, value)
+      return "Path=/; HttpOnly"
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.10 b/examples/LUA_project/application.lua.10
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.10
@@ -0,0 +1,655 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      return fn(self)
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.11 b/examples/LUA_project/application.lua.11
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.11
@@ -0,0 +1,655 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      return fn(self)
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.12 b/examples/LUA_project/application.lua.12
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.12
@@ -0,0 +1,652 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      return fn(self)
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.13 b/examples/LUA_project/application.lua.13
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.13
@@ -0,0 +1,649 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      return fn(self)
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.14 b/examples/LUA_project/application.lua.14
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.14
@@ -0,0 +1,645 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.15 b/examples/LUA_project/application.lua.15
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.15
@@ -0,0 +1,659 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.16 b/examples/LUA_project/application.lua.16
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.16
@@ -0,0 +1,659 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.17 b/examples/LUA_project/application.lua.17
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.17
@@ -0,0 +1,659 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json") then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.18 b/examples/LUA_project/application.lua.18
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.18
@@ -0,0 +1,659 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if content_type:lower() == "application/json" then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.19 b/examples/LUA_project/application.lua.19
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.19
@@ -0,0 +1,655 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json_safe = require("cjson.safe")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if content_type:lower() == "application/json" then
+          local obj, err = json_safe.decode(ngx.req.get_body_data())
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.2 b/examples/LUA_project/application.lua.2
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.2
@@ -0,0 +1,724 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local lapis_config = require("lapis.config")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local increment_perf
+do
+  local _obj_0 = require("lapis.nginx.context")
+  increment_perf = _obj_0.increment_perf
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        local config = lapis_config.get()
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local start_time
+        if config.measure_performance then
+          ngx.update_time()
+          start_time = ngx.now()
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+        if start_time then
+          ngx.update_time()
+          increment_perf("view_time", ngx.now() - start_time)
+        end
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+        do
+          local extra = self.app.cookie_attributes(self, k, v)
+          if extra then
+            cookie = cookie .. ("; " .. extra)
+          end
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      local config = lapis_config.get()
+      if config._name == "test" then
+        local param_dump = logger.flatten_params(self.url_params)
+        r.res:add_header("X-Lapis-Error", "true")
+        r:write({
+          status = 500,
+          json = {
+            status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump),
+            err = err,
+            trace = trace
+          }
+        })
+      else
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          error_page({
+            status = 500,
+            err = err,
+            trace = trace
+          })
+        })
+      end
+      r:render()
+      logger.request(r)
+      return r
+    end,
+    cookie_attributes = function(self, name, value)
+      return "Path=/; HttpOnly"
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.20 b/examples/LUA_project/application.lua.20
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.20
@@ -0,0 +1,597 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json_safe = require("cjson.safe")
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if content_type:lower() == "application/json" then
+          local obj, err = json_safe.decode(ngx.req.get_body_data())
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.21 b/examples/LUA_project/application.lua.21
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.21
@@ -0,0 +1,578 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.22 b/examples/LUA_project/application.lua.22
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.22
@@ -0,0 +1,580 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = error_response or fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.23 b/examples/LUA_project/application.lua.23
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.23
@@ -0,0 +1,580 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.24 b/examples/LUA_project/application.lua.24
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.24
@@ -0,0 +1,575 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.25 b/examples/LUA_project/application.lua.25
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.25
@@ -0,0 +1,564 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.26 b/examples/LUA_project/application.lua.26
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.26
@@ -0,0 +1,561 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.27 b/examples/LUA_project/application.lua.27
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.27
@@ -0,0 +1,545 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.28 b/examples/LUA_project/application.lua.28
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.28
@@ -0,0 +1,545 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        do
+          local parent = cls.__parent
+          if parent then
+            add_routes(parent)
+          end
+        end
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.29 b/examples/LUA_project/application.lua.29
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.29
@@ -0,0 +1,559 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_routes
+      add_routes = function(cls)
+        do
+          local parent = cls.__parent
+          if parent then
+            add_routes(parent)
+          end
+        end
+        for path, handler in pairs(cls.__base) do
+          local t = type(path)
+          if t == "table" or t == "string" and path:match("^/") then
+            self.router:add_route(path, self:wrap_handler(handler))
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.3 b/examples/LUA_project/application.lua.3
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.3
@@ -0,0 +1,708 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+        do
+          local extra = self.app.cookie_attributes(self, k, v)
+          if extra then
+            cookie = cookie .. ("; " .. extra)
+          end
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      local config = require("lapis.config").get()
+      if config._name == "test" then
+        local param_dump = logger.flatten_params(self.url_params)
+        r.res:add_header("X-Lapis-Error", "true")
+        r:write({
+          status = 500,
+          json = {
+            status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump),
+            err = err,
+            trace = trace
+          }
+        })
+      else
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          error_page({
+            status = 500,
+            err = err,
+            trace = trace
+          })
+        })
+      end
+      r:render()
+      logger.request(r)
+      return r
+    end,
+    cookie_attributes = function(self, name, value)
+      return "Path=/; HttpOnly"
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.30 b/examples/LUA_project/application.lua.30
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.30
@@ -0,0 +1,546 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.31 b/examples/LUA_project/application.lua.31
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.31
@@ -0,0 +1,546 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.32 b/examples/LUA_project/application.lua.32
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.32
@@ -0,0 +1,556 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.33 b/examples/LUA_project/application.lua.33
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.33
@@ -0,0 +1,558 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.34 b/examples/LUA_project/application.lua.34
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.34
@@ -0,0 +1,570 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts
+      do
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        parts = _accum_0
+      end
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          for _index_0 = 1, #extra do
+            local p = extra[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.35 b/examples/LUA_project/application.lua.35
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.35
@@ -0,0 +1,600 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.36 b/examples/LUA_project/application.lua.36
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.36
@@ -0,0 +1,600 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.37 b/examples/LUA_project/application.lua.37
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.37
@@ -0,0 +1,600 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local capture_errors, capture_errors_json
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  local out
+  out = function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+  do
+    local error_response = tbl.on_error
+    if error_response then
+      out = capture_errors(out, error_response)
+    end
+  end
+  return out
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.38 b/examples/LUA_project/application.lua.38
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.38
@@ -0,0 +1,589 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                filter(r)
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          if run_before_filter(before, self) then
+            return 
+          end
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.39 b/examples/LUA_project/application.lua.39
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.39
@@ -0,0 +1,575 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                filter(r)
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.4 b/examples/LUA_project/application.lua.4
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.4
@@ -0,0 +1,706 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+        do
+          local extra = self.app.cookie_attributes(self, k, v)
+          if extra then
+            cookie = cookie .. ("; " .. extra)
+          end
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      local config = require("lapis.config").get()
+      if config._name == "test" then
+        r.res:add_header("X-Lapis-Error", "true")
+        r:write({
+          status = 500,
+          json = {
+            err = err,
+            trace = trace
+          }
+        })
+      else
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          error_page({
+            status = 500,
+            err = err,
+            trace = trace
+          })
+        })
+      end
+      r:render()
+      logger.request(r)
+      return r
+    end,
+    cookie_attributes = function(self, name, value)
+      return "Path=/; HttpOnly"
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.40 b/examples/LUA_project/application.lua.40
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.40
@@ -0,0 +1,575 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      if not (#parts > 0) then
+        return 
+      end
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                filter(r)
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.41 b/examples/LUA_project/application.lua.41
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.41
@@ -0,0 +1,572 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                filter(r)
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.42 b/examples/LUA_project/application.lua.42
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.42
@@ -0,0 +1,577 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              local _list_0 = before_filters
+              for _index_0 = 1, #_list_0 do
+                local filter = _list_0[_index_0]
+                filter(r)
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.43 b/examples/LUA_project/application.lua.43
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.43
@@ -0,0 +1,554 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local t = type(path)
+      if t == "table" then
+        if path_prefix then
+          local name = next(path)
+          path[name] = path_prefix .. path[name]
+        end
+        if name_prefix then
+          local name = next(path)
+          path[name_prefix .. name] = path[name]
+          path[name] = nil
+        end
+        into[path] = action
+      elseif t == "string" and path:match("^/") then
+        if path_prefix then
+          path = path_prefix .. path
+        end
+        into[path] = action
+      end
+    end
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.44 b/examples/LUA_project/application.lua.44
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.44
@@ -0,0 +1,527 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.45 b/examples/LUA_project/application.lua.45
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.45
@@ -0,0 +1,527 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local widget = self.options.render
+        if widget then
+          if widget == true then
+            widget = self.route_name
+          end
+          if type(widget) == "string" then
+            widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          end
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.46 b/examples/LUA_project/application.lua.46
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.46
@@ -0,0 +1,525 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.47 b/examples/LUA_project/application.lua.47
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.47
@@ -0,0 +1,525 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path:match("^%a+:") then
+        return path
+      end
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.48 b/examples/LUA_project/application.lua.48
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.48
@@ -0,0 +1,522 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.49 b/examples/LUA_project/application.lua.49
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.49
@@ -0,0 +1,520 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json, build_url
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          do
+            local old_query = parsed.query
+            if old_query then
+              parsed.query = old_query .. "&" .. query
+            else
+              parsed.query = query
+            end
+          end
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.5 b/examples/LUA_project/application.lua.5
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.5
@@ -0,0 +1,694 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+        do
+          local extra = self.app.cookie_attributes(self, k, v)
+          if extra then
+            cookie = cookie .. ("; " .. extra)
+          end
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end,
+    cookie_attributes = function(self, name, value)
+      return "Path=/; HttpOnly"
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.50 b/examples/LUA_project/application.lua.50
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.50
@@ -0,0 +1,516 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.51 b/examples/LUA_project/application.lua.51
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.51
@@ -0,0 +1,516 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              filter(r)
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.52 b/examples/LUA_project/application.lua.52
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.52
@@ -0,0 +1,514 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      do
+        local extra = self.app.cookie_attributes
+        if extra then
+          i = i + 3
+          local _list_0 = extra
+          for _index_0 = 1, #_list_0 do
+            local p = _list_0[_index_0]
+            parts[i] = p
+            i = i + 1
+          end
+        end
+      end
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.53 b/examples/LUA_project/application.lua.53
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.53
@@ -0,0 +1,502 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.54 b/examples/LUA_project/application.lua.54
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.54
@@ -0,0 +1,502 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace)
+      local r = Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        self.app.error_page({
+          staus = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.55 b/examples/LUA_project/application.lua.55
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.55
@@ -0,0 +1,498 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return self.app:handle_404()
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.56 b/examples/LUA_project/application.lua.56
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.56
@@ -0,0 +1,495 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string, to_json
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.57 b/examples/LUA_project/application.lua.57
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.57
@@ -0,0 +1,496 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = json.encode(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          content_type = "text/html",
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.58 b/examples/LUA_project/application.lua.58
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.58
@@ -0,0 +1,495 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = json.encode(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.59 b/examples/LUA_project/application.lua.59
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.59
@@ -0,0 +1,495 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = json.encode(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        url = self.options.redirect_to
+        if url then
+          if url:match("^/") then
+            url = self:build_url(url)
+          end
+          self.res:add_header("Location", url)
+          self.res.status = 302
+        end
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.6 b/examples/LUA_project/application.lua.6
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.6
@@ -0,0 +1,692 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local insert
+do
+  local _obj_0 = table
+  insert = _obj_0.insert
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.ordered_routes = self.ordered_routes or { }
+      local key
+      if route_name then
+        local tuple = self.ordered_routes[route_name]
+        do
+          local old_path = tuple and tuple[next(tuple)]
+          if old_path then
+            if old_path ~= path then
+              error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")")
+            end
+          end
+        end
+        if tuple then
+          key = tuple
+        else
+          tuple = {
+            [route_name] = path
+          }
+          self.ordered_routes[route_name] = tuple
+          key = tuple
+        end
+      else
+        key = path
+      end
+      if not (self[key]) then
+        insert(self.ordered_routes, key)
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        do
+          local ordered = self.ordered_routes
+          if ordered then
+            for _index_0 = 1, #ordered do
+              local path = ordered[_index_0]
+              add_route(path, self[path])
+            end
+          else
+            for path, handler in pairs(self) do
+              add_route(path, handler)
+            end
+          end
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.60 b/examples/LUA_project/application.lua.60
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.60
@@ -0,0 +1,486 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params())
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.61 b/examples/LUA_project/application.lua.61
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.61
@@ -0,0 +1,482 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.62 b/examples/LUA_project/application.lua.62
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.62
@@ -0,0 +1,481 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        if query then
+          path = _path
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.63 b/examples/LUA_project/application.lua.63
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.63
@@ -0,0 +1,480 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path then
+        local query
+        path, query = path:match("(.-)%?(.*)")
+        if query then
+          parsed.query = query
+        end
+        if not path:match("^/") then
+          path = "/" .. tostring(path)
+        end
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.64 b/examples/LUA_project/application.lua.64
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.64
@@ -0,0 +1,473 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      local i = #parts
+      parts[i + 1] = "Path=/"
+      parts[i + 2] = "HttpOnly"
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.65 b/examples/LUA_project/application.lua.65
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.65
@@ -0,0 +1,470 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        local layout = layout_cls({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.66 b/examples/LUA_project/application.lua.66
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.66
@@ -0,0 +1,463 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.67 b/examples/LUA_project/application.lua.67
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.67
@@ -0,0 +1,457 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.68 b/examples/LUA_project/application.lua.68
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.68
@@ -0,0 +1,453 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.69 b/examples/LUA_project/application.lua.69
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.69
@@ -0,0 +1,436 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.7 b/examples/LUA_project/application.lua.7
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.7
@@ -0,0 +1,658 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-Type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-Type"] = ct
+        end
+      end
+      if not self.res.headers["Content-Type"] then
+        self.res.headers["Content-Type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-Cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.70 b/examples/LUA_project/application.lua.70
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.70
@@ -0,0 +1,436 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 1
+        for k, v in pairs(self.cookies) do
+          _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          _len_0 = _len_0 + 1
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.71 b/examples/LUA_project/application.lua.71
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.71
@@ -0,0 +1,439 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+local capture_errors
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local capture_errors_json
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.72 b/examples/LUA_project/application.lua.72
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.72
@@ -0,0 +1,421 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local capture_errors
+capture_errors = function(fn)
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return {
+          render = true
+        }
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.73 b/examples/LUA_project/application.lua.73
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.73
@@ -0,0 +1,417 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      do
+        local before = tbl.before
+        if before then
+          before(self)
+        end
+      end
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local capture_errors
+capture_errors = function(fn)
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      self.errors = {
+        unpack(out, 2)
+      }
+      return {
+        render = true
+      }
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    coroutine.yield(msg)
+  end
+  return thing
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield(msg)
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.74 b/examples/LUA_project/application.lua.74
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.74
@@ -0,0 +1,411 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+local capture_errors
+capture_errors = function(fn)
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      self.errors = {
+        unpack(out, 2)
+      }
+      return {
+        render = true
+      }
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+local assert_error
+assert_error = function(thing, msg)
+  if not (thing) then
+    coroutine.yield(msg)
+  end
+  return thing
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield(msg)
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.75 b/examples/LUA_project/application.lua.75
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.75
@@ -0,0 +1,375 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          r:write(handler({ }, nil, "default_route", r))
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.cmd_url:match("./$") then
+        local stripped = self.req.cmd_url:match("^(.+)/+$")
+        return {
+          redirect_to = stripped,
+          status = 301
+        }
+      else
+        return error("Failed to find route: " .. tostring(self.req.cmd_url))
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.76 b/examples/LUA_project/application.lua.76
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.76
@@ -0,0 +1,358 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        self.router:resolve(req.parsed_url.path, r)
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+        logger.request(r)
+      end
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.77 b/examples/LUA_project/application.lua.77
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.77
@@ -0,0 +1,357 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace
+      local success = xpcall((function()
+        local r = Request(self, req, res)
+        self.router:resolve(req.parsed_url.path, r)
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        local r = Request(self, req, res)
+        r:write({
+          status = 500,
+          layout = false,
+          self.error_page({
+            staus = 500,
+            err = err,
+            trace = trace
+          })
+        })
+        r:render()
+      end
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.78 b/examples/LUA_project/application.lua.78
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.78
@@ -0,0 +1,331 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.views.layout"),
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.79 b/examples/LUA_project/application.lua.79
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.79
@@ -0,0 +1,331 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.8 b/examples/LUA_project/application.lua.8
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.8
@@ -0,0 +1,658 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      if type(fn) == "function" then
+        return fn(self)
+      end
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.80 b/examples/LUA_project/application.lua.80
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.80
@@ -0,0 +1,330 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          view:include_helper(self)
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.81 b/examples/LUA_project/application.lua.81
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.81
@@ -0,0 +1,345 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          local view = widget(self.options.locals)
+          if not (self.options.locals) then
+            for k, v in pairs(self) do
+              local _continue_0 = false
+              repeat
+                if k == "buffer" or k == "options" then
+                  _continue_0 = true
+                  break
+                end
+                view[k] = v
+                _continue_0 = true
+              until true
+              if not _continue_0 then
+                break
+              end
+            end
+          end
+          self:write(view)
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.82 b/examples/LUA_project/application.lua.82
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.82
@@ -0,0 +1,328 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      do
+        local rpath = self.options.render
+        if rpath then
+          if rpath == true then
+            rpath = self.route_name
+          end
+          local view = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath))
+          self:write(view(self.options.locals or self))
+        end
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    views_prefix = "views",
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.83 b/examples/LUA_project/application.lua.83
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.83
@@ -0,0 +1,317 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local session = require("lapis.session")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local auto_table
+auto_table = function(fn)
+  return setmetatable({ }, {
+    __index = function(self, name)
+      local result = fn()
+      setmetatable(self, {
+        __index = result
+      })
+      return result[name]
+    end
+  })
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = auto_table(function()
+        return session.get_session(self)
+      end)
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.84 b/examples/LUA_project/application.lua.84
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.84
@@ -0,0 +1,306 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local parse_cookie_string
+do
+  local _table_0 = require("lapis.util")
+  parse_cookie_string = _table_0.parse_cookie_string
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      self:write_cookies()
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      local parts = (function()
+        local _accum_0 = { }
+        local _len_0 = 0
+        for k, v in pairs(self.cookies) do
+          local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v))
+          if _value_0 ~= nil then
+            _len_0 = _len_0 + 1
+            _accum_0[_len_0] = _value_0
+          end
+        end
+        return _accum_0
+      end)()
+      return self.res:add_header("Set-cookie", table.concat(parts, "; "))
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = setmetatable({ }, {
+        __index = function(tbl, name)
+          local parsed = parse_cookie_string(self.req.headers.cookie)
+          setmetatable(self.cookies, {
+            __index = parsed
+          })
+          return parsed[name]
+        end
+      })
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.85 b/examples/LUA_project/application.lua.85
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.85
@@ -0,0 +1,276 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+local respond_to
+respond_to = function(tbl)
+  return function(self)
+    local fn = tbl[self.req.cmd_mth]
+    if fn then
+      return fn(self)
+    else
+      return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+    end
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to
+}
diff --git a/examples/LUA_project/application.lua.86 b/examples/LUA_project/application.lua.86
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.86
@@ -0,0 +1,264 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    before_filters = { },
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          local _list_0 = self.before_filters
+          for _index_0 = 1, #_list_0 do
+            local filter = _list_0[_index_0]
+            filter(r)
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.before_filter = function(self, fn)
+    return table.insert(self.before_filters, fn)
+  end
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+return {
+  Request = Request,
+  Application = Application
+}
diff --git a/examples/LUA_project/application.lua.87 b/examples/LUA_project/application.lua.87
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.87
@@ -0,0 +1,254 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local json = require("cjson")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if self.options.json then
+        self.res.headers["Content-type"] = "application/json"
+        self.res.content = json.encode(self.options.json)
+        return 
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+return {
+  Request = Request,
+  Application = Application
+}
diff --git a/examples/LUA_project/application.lua.88 b/examples/LUA_project/application.lua.88
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.88
@@ -0,0 +1,248 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.options.redirect_to then
+        self.res:add_header("Location", self:build_url(self.options.redirect_to))
+        self.res.status = 302
+      end
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    build_url = function(self, path, options)
+      local parsed = (function()
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        return _tbl_0
+      end)()
+      parsed.authority = nil
+      if path and not path:match("^/") then
+        path = "/" .. tostring(path)
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return url.build(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write:", tostring(thing))
+        end
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+return {
+  Request = Request,
+  Application = Application
+}
diff --git a/examples/LUA_project/application.lua.89 b/examples/LUA_project/application.lua.89
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.89
@@ -0,0 +1,211 @@
+local logger = require("lapis.logging")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    write = function(self, thing)
+      local t = type(thing)
+      if t == "table" then
+        local mt = getmetatable(thing)
+        if mt and mt.__call then
+          t = "function"
+        end
+      end
+      local _exp_0 = t
+      if "string" == _exp_0 then
+        return table.insert(self.buffer, thing)
+      elseif "table" == _exp_0 then
+        for k, v in pairs(thing) do
+          if type(k) == "string" then
+            self.options[k] = v
+          else
+            self:write(v)
+          end
+        end
+      elseif "function" == _exp_0 then
+        return self:write(thing(self.buffer))
+      elseif "nil" == _exp_0 then
+        return nil
+      else
+        return error("Don't know how to write:", tostring(thing))
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+return {
+  Request = Request,
+  Application = Application
+}
diff --git a/examples/LUA_project/application.lua.9 b/examples/LUA_project/application.lua.9
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.9
@@ -0,0 +1,656 @@
+local logger = require("lapis.logging")
+local url = require("socket.url")
+local session = require("lapis.session")
+local Router
+do
+  local _obj_0 = require("lapis.router")
+  Router = _obj_0.Router
+end
+local html_writer
+do
+  local _obj_0 = require("lapis.html")
+  html_writer = _obj_0.html_writer
+end
+local parse_cookie_string, to_json, build_url, auto_table
+do
+  local _obj_0 = require("lapis.util")
+  parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table
+end
+local json = require("cjson")
+local capture_errors, capture_errors_json, respond_to
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local run_before_filter
+run_before_filter = function(filter, r)
+  local _write = r.write
+  local written = false
+  r.write = function(...)
+    written = true
+    return _write(...)
+  end
+  filter(r)
+  r.write = nil
+  return written
+end
+local Request
+do
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        do
+          local front = k:match("^([^%[]+)%[")
+          if front then
+            local curr = self.params
+            for match in k:gmatch("%[(.-)%]") do
+              local new = curr[front]
+              if new == nil then
+                new = { }
+                curr[front] = new
+              end
+              curr = new
+              front = match
+            end
+            curr[front] = v
+          else
+            self.params[k] = v
+          end
+        end
+      end
+    end,
+    render = function(self, opts)
+      if opts == nil then
+        opts = false
+      end
+      if opts then
+        self.options = opts
+      end
+      session.write_session(self)
+      self:write_cookies()
+      if self.options.status then
+        self.res.status = self.options.status
+      end
+      do
+        local obj = self.options.json
+        if obj then
+          self.res.headers["Content-type"] = "application/json"
+          self.res.content = to_json(obj)
+          return 
+        end
+      end
+      do
+        local ct = self.options.content_type
+        if ct then
+          self.res.headers["Content-type"] = ct
+        end
+      end
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      do
+        local redirect_url = self.options.redirect_to
+        if redirect_url then
+          if redirect_url:match("^/") then
+            redirect_url = self:build_url(redirect_url)
+          end
+          self.res:add_header("Location", redirect_url)
+          self.res.status = self.res.status or 302
+          return ""
+        end
+      end
+      local has_layout = self.app.layout and set_and_truthy(self.options.layout, true)
+      if has_layout then
+        self.layout_opts = {
+          inner = nil
+        }
+      end
+      local widget = self.options.render
+      if widget == true then
+        widget = self.route_name
+      end
+      if widget then
+        if type(widget) == "string" then
+          widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget))
+        end
+        local view = widget(self.options.locals)
+        if self.layout_opts then
+          self.layout_opts.view_widget = view
+        end
+        view:include_helper(self)
+        self:write(view)
+      end
+      if has_layout then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout_path = self.options.layout
+        local layout_cls
+        if type(layout_path) == "string" then
+          layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path))
+        else
+          layout_cls = self.app.layout
+        end
+        self.layout_opts.inner = self.layout_opts.inner or function()
+          return raw(inner)
+        end
+        local layout = layout_cls(self.layout_opts)
+        layout:include_helper(self)
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, first, ...)
+      if type(first) == "table" then
+        return self.app.router:url_for(first:url_params(self, ...))
+      else
+        return self.app.router:url_for(first, ...)
+      end
+    end,
+    build_url = function(self, path, options)
+      if path and path:match("^%a+:") then
+        return path
+      end
+      local parsed
+      do
+        local _tbl_0 = { }
+        for k, v in pairs(self.req.parsed_url) do
+          _tbl_0[k] = v
+        end
+        parsed = _tbl_0
+      end
+      parsed.query = nil
+      if path then
+        local _path, query = path:match("^(.-)%?(.*)$")
+        path = _path or path
+        parsed.query = query
+      end
+      parsed.path = path
+      if parsed.port == "80" then
+        parsed.port = nil
+      end
+      if options then
+        for k, v in pairs(options) do
+          parsed[k] = v
+        end
+      end
+      return build_url(parsed)
+    end,
+    write = function(self, ...)
+      local _list_0 = {
+        ...
+      }
+      for _index_0 = 1, #_list_0 do
+        local thing = _list_0[_index_0]
+        local t = type(thing)
+        if t == "table" then
+          local mt = getmetatable(thing)
+          if mt and mt.__call then
+            t = "function"
+          end
+        end
+        local _exp_0 = t
+        if "string" == _exp_0 then
+          table.insert(self.buffer, thing)
+        elseif "table" == _exp_0 then
+          for k, v in pairs(thing) do
+            if type(k) == "string" then
+              self.options[k] = v
+            else
+              self:write(v)
+            end
+          end
+        elseif "function" == _exp_0 then
+          self:write(thing(self.buffer))
+        elseif "nil" == _exp_0 then
+          local _ = nil
+        else
+          error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing))
+        end
+      end
+    end,
+    write_cookies = function(self)
+      if not (next(self.cookies)) then
+        return 
+      end
+      local extra = self.app.cookie_attributes
+      if extra then
+        extra = "; " .. table.concat(self.app.cookie_attributes, "; ")
+      end
+      for k, v in pairs(self.cookies) do
+        local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly"
+        if extra then
+          cookie = cookie .. extra
+        end
+        self.res:add_header("Set-cookie", cookie)
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+      self.cookies = auto_table(function()
+        return parse_cookie_string(self.req.headers.cookie)
+      end)
+      self.session = session.lazy_session(self)
+    end,
+    __base = _base_0,
+    __name = "Request"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  Request = _class_0
+end
+local Application
+do
+  local _base_0 = {
+    Request = Request,
+    layout = require("lapis.views.layout"),
+    error_page = require("lapis.views.error"),
+    views_prefix = "views",
+    enable = function(self, feature)
+      local fn = require("lapis.features." .. tostring(feature))
+      return fn(self)
+    end,
+    match = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      local key
+      if route_name then
+        key = {
+          [route_name] = path
+        }
+      else
+        key = path
+      end
+      self[key] = handler
+      self.router = nil
+      return handler
+    end,
+    build_router = function(self)
+      self.router = Router()
+      self.router.default_route = function(self)
+        return false
+      end
+      local add_route
+      add_route = function(path, handler)
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          return self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+      local add_routes
+      add_routes = function(cls)
+        for path, handler in pairs(cls.__base) do
+          add_route(path, handler)
+        end
+        for path, handler in pairs(self) do
+          add_route(path, handler)
+        end
+        do
+          local parent = cls.__parent
+          if parent then
+            return add_routes(parent)
+          end
+        end
+      end
+      return add_routes(self.__class)
+    end,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(r.req.params_get, "GET")
+          _with_0:add_params(r.req.params_post, "POST")
+          _with_0:add_params(params, "url_params")
+          if self.before_filters then
+            local _list_0 = self.before_filters
+            for _index_0 = 1, #_list_0 do
+              local filter = _list_0[_index_0]
+              if run_before_filter(filter, r) then
+                return r
+              end
+            end
+          end
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local err, trace, r
+      local success = xpcall((function()
+        r = self.Request(self, req, res)
+        if not (self.router:resolve(req.parsed_url.path, r)) then
+          local handler = self:wrap_handler(self.default_route)
+          handler({ }, nil, "default_route", r)
+        end
+        r:render()
+        return logger.request(r)
+      end), function(_err)
+        err = _err
+        trace = debug.traceback("", 2)
+      end)
+      if not (success) then
+        self.handle_error(r, err, trace)
+      end
+      return res
+    end,
+    serve = function(self) end,
+    default_route = function(self)
+      if self.req.parsed_url.path:match("./$") then
+        local stripped = self.req.parsed_url.path:match("^(.+)/+$")
+        return {
+          redirect_to = self:build_url(stripped, {
+            query = self.req.parsed_url.query
+          }),
+          status = 301
+        }
+      else
+        return self.app.handle_404(self)
+      end
+    end,
+    handle_404 = function(self)
+      return error("Failed to find route: " .. tostring(self.req.cmd_url))
+    end,
+    handle_error = function(self, err, trace, error_page)
+      if error_page == nil then
+        error_page = self.app.error_page
+      end
+      local r = self.app.Request(self, self.req, self.res)
+      r:write({
+        status = 500,
+        layout = false,
+        content_type = "text/html",
+        error_page({
+          status = 500,
+          err = err,
+          trace = trace
+        })
+      })
+      r:render()
+      logger.request(r)
+      return r
+    end
+  }
+  _base_0.__index = _base_0
+  local _class_0 = setmetatable({
+    __init = function(self)
+      return self:build_router()
+    end,
+    __base = _base_0,
+    __name = "Application"
+  }, {
+    __index = _base_0,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.find_action = function(self, name)
+    self._named_route_cache = self._named_route_cache or { }
+    local route = self._named_route_cache[name]
+    if not (route) then
+      for app_route in pairs(self.__base) do
+        if type(app_route) == "table" then
+          local app_route_name = next(app_route)
+          self._named_route_cache[app_route_name] = app_route
+          if app_route_name == name then
+            route = app_route
+          end
+        end
+      end
+    end
+    return route and self[route], route
+  end
+  local _list_0 = {
+    "get",
+    "post",
+    "delete",
+    "put"
+  }
+  for _index_0 = 1, #_list_0 do
+    local meth = _list_0[_index_0]
+    local upper_meth = meth:upper()
+    self.__base[meth] = function(self, route_name, path, handler)
+      if handler == nil then
+        handler = path
+        path = route_name
+        route_name = nil
+      end
+      self.responders = self.responders or { }
+      local existing = self.responders[route_name or path]
+      local tbl = {
+        [upper_meth] = handler
+      }
+      if existing then
+        setmetatable(tbl, {
+          __index = function(self, key)
+            if key:match("%u") then
+              return existing
+            end
+          end
+        })
+      end
+      local responder = respond_to(tbl)
+      self.responders[route_name or path] = responder
+      return self:match(route_name, path, responder)
+    end
+  end
+  self.before_filter = function(self, fn)
+    self.__base.before_filters = self.__base.before_filters or { }
+    return table.insert(self.before_filters, fn)
+  end
+  self.include = function(self, other_app, opts, into)
+    if into == nil then
+      into = self.__base
+    end
+    if type(other_app) == "string" then
+      other_app = require(other_app)
+    end
+    local path_prefix = opts and opts.path or other_app.path
+    local name_prefix = opts and opts.name or other_app.name
+    for path, action in pairs(other_app.__base) do
+      local _continue_0 = false
+      repeat
+        local t = type(path)
+        if t == "table" then
+          if path_prefix then
+            local name = next(path)
+            path[name] = path_prefix .. path[name]
+          end
+          if name_prefix then
+            local name = next(path)
+            path[name_prefix .. name] = path[name]
+            path[name] = nil
+          end
+        elseif t == "string" and path:match("^/") then
+          if path_prefix then
+            path = path_prefix .. path
+          end
+        else
+          _continue_0 = true
+          break
+        end
+        do
+          local before_filters = other_app.before_filters
+          if before_filters then
+            local fn = action
+            action = function(r)
+              for _index_0 = 1, #before_filters do
+                local filter = before_filters[_index_0]
+                if run_before_filter(filter, r) then
+                  return 
+                end
+              end
+              return fn(r)
+            end
+          end
+        end
+        into[path] = action
+        _continue_0 = true
+      until true
+      if not _continue_0 then
+        break
+      end
+    end
+  end
+  Application = _class_0
+end
+do
+  local default_head
+  default_head = function()
+    return {
+      layout = false
+    }
+  end
+  respond_to = function(tbl)
+    if not (tbl.HEAD) then
+      tbl.HEAD = default_head
+    end
+    local out
+    out = function(self)
+      local fn = tbl[self.req.cmd_mth]
+      if fn then
+        do
+          local before = tbl.before
+          if before then
+            if run_before_filter(before, self) then
+              return 
+            end
+          end
+        end
+        return fn(self)
+      else
+        return error("don't know how to respond to " .. tostring(self.req.cmd_mth))
+      end
+    end
+    do
+      local error_response = tbl.on_error
+      if error_response then
+        out = capture_errors(out, error_response)
+      end
+    end
+    return out, tbl
+  end
+end
+local default_error_response
+default_error_response = function()
+  return {
+    render = true
+  }
+end
+capture_errors = function(fn, error_response)
+  if error_response == nil then
+    error_response = default_error_response
+  end
+  if type(fn) == "table" then
+    error_response = fn.on_error or error_response
+    fn = fn[1]
+  end
+  return function(self, ...)
+    local co = coroutine.create(fn)
+    local out = {
+      coroutine.resume(co, self)
+    }
+    if not (out[1]) then
+      error(debug.traceback(co, out[2]))
+    end
+    if coroutine.status(co) == "suspended" then
+      if out[2] == "error" then
+        self.errors = out[3]
+        return error_response(self)
+      else
+        return error("Unknown yield")
+      end
+    else
+      return unpack(out, 2)
+    end
+  end
+end
+capture_errors_json = function(fn)
+  return capture_errors(fn, function(self)
+    return {
+      json = {
+        errors = self.errors
+      }
+    }
+  end)
+end
+local yield_error
+yield_error = function(msg)
+  return coroutine.yield("error", {
+    msg
+  })
+end
+local assert_error
+assert_error = function(thing, msg, ...)
+  if not (thing) then
+    yield_error(msg)
+  end
+  return thing, msg, ...
+end
+local json_params
+json_params = function(fn)
+  return function(self, ...)
+    do
+      local content_type = self.req.headers["content-type"]
+      if content_type then
+        if string.find(content_type:lower(), "application/json", nil, true) then
+          local obj
+          pcall(function()
+            local err
+            obj, err = json.decode(ngx.req.get_body_data())
+          end)
+          if obj then
+            self:add_params(obj, "json")
+          end
+        end
+      end
+    end
+    return fn(self, ...)
+  end
+end
+return {
+  Request = Request,
+  Application = Application,
+  respond_to = respond_to,
+  capture_errors = capture_errors,
+  capture_errors_json = capture_errors_json,
+  json_params = json_params,
+  assert_error = assert_error,
+  yield_error = yield_error
+}
diff --git a/examples/LUA_project/application.lua.90 b/examples/LUA_project/application.lua.90
new file mode 100644
--- /dev/null
+++ b/examples/LUA_project/application.lua.90
@@ -0,0 +1,209 @@
+local logger = require("lapis.logging")
+local Router
+do
+  local _table_0 = require("lapis.router")
+  Router = _table_0.Router
+end
+local html_writer
+do
+  local _table_0 = require("lapis.html")
+  html_writer = _table_0.html_writer
+end
+local set_and_truthy
+set_and_truthy = function(val, default)
+  if default == nil then
+    default = true
+  end
+  if val == nil then
+    return default
+  end
+  return val
+end
+local Request
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    add_params = function(self, params, name)
+      self[name] = params
+      for k, v in pairs(params) do
+        self.params[k] = v
+      end
+    end,
+    render = function(self)
+      if not self.res.headers["Content-type"] then
+        self.res.headers["Content-type"] = "text/html"
+      end
+      if self.app.layout and set_and_truthy(self.options.layout, true) then
+        local inner = self.buffer
+        self.buffer = { }
+        local layout = self.app.layout({
+          inner = function()
+            return raw(inner)
+          end
+        })
+        layout:render(self.buffer)
+      end
+      if next(self.buffer) then
+        local content = table.concat(self.buffer)
+        if self.res.content then
+          self.res.content = self.res.content .. content
+        else
+          self.res.content = content
+        end
+      end
+    end,
+    html = function(self, fn)
+      return html_writer(fn)
+    end,
+    url_for = function(self, ...)
+      return self.app.router:url_for(...)
+    end,
+    write = function(self, thing)
+      local t = type(thing)
+      if t == "table" then
+        local mt = getmetatable(thing)
+        if mt and mt.__call then
+          t = "function"
+        end
+      end
+      local _exp_0 = t
+      if "string" == _exp_0 then
+        return table.insert(self.buffer, thing)
+      elseif "table" == _exp_0 then
+        for k, v in pairs(thing) do
+          if type(k) == "string" then
+            self.options[k] = v
+          else
+            self:write(v)
+          end
+        end
+      elseif "function" == _exp_0 then
+        return self:write(thing(self.buffer))
+      elseif "nil" == _exp_0 then
+        return nil
+      else
+        return error("Don't know how to write:", tostring(thing))
+      end
+    end,
+    _debug = function(self)
+      self.buffer = {
+        "<html>",
+        "req:",
+        "<pre>",
+        moon.dump(self.req),
+        "</pre>",
+        "res:",
+        "<pre>",
+        moon.dump(self.res),
+        "</pre>",
+        "</html>"
+      }
+    end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self, app, req, res)
+      self.app, self.req, self.res = app, req, res
+      self.buffer = { }
+      self.params = { }
+      self.options = { }
+    end,
+    __base = _base_0,
+    __name = "Request",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Request = _class_0
+end
+local Application
+do
+  local _parent_0 = nil
+  local _base_0 = {
+    layout = require("lapis.layout").Default,
+    wrap_handler = function(self, handler)
+      return function(params, path, name, r)
+        do
+          local _with_0 = r
+          _with_0.route_name = name
+          _with_0:add_params(params, "url_params")
+          _with_0:write(handler(r))
+          return _with_0
+        end
+      end
+    end,
+    dispatch = function(self, req, res)
+      local r = Request(self, req, res)
+      self.router:resolve(req.parsed_url.path, r)
+      r:render()
+      logger.request(r)
+      return res
+    end,
+    serve = function(self) end
+  }
+  _base_0.__index = _base_0
+  if _parent_0 then
+    setmetatable(_base_0, _parent_0.__base)
+  end
+  local _class_0 = setmetatable({
+    __init = function(self)
+      self.router = Router()
+      do
+        local _with_0 = require("lapis.server")
+        self.__class.__base["/static/*"] = _with_0.make_static_handler("static")
+        self.__class.__base["/favicon.ico"] = _with_0.serve_from_static()
+      end
+      for path, handler in pairs(self.__class.__base) do
+        local t = type(path)
+        if t == "table" or t == "string" and path:match("^/") then
+          self.router:add_route(path, self:wrap_handler(handler))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "Application",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil and _parent_0 then
+        return _parent_0[name]
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0 and _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  Application = _class_0
+end
+return {
+  Request = Request,
+  Application = Application
+}
diff --git a/examples/Lang.lhs b/examples/Lang.lhs
--- a/examples/Lang.lhs
+++ b/examples/Lang.lhs
@@ -1,368 +1,368 @@
-Source: http://www.haskell.org/haskellwiki/Parsing_a_simple_imperative_language
-
-This tutorial will present how to parse a subset of a simple imperative
-programming language called W<small>HILE</small> (introduced in a book
-"Principles of Program Analysis" by Nielson, Nielson and Hankin). It includes
-only a few statements and basic boolean/arithmetic expressions, which makes it
-a nice material for a tutorial.
-
-== Imports ==
-
-First let's specify the name of the module:
-
-<haskell>
-
-> module Lang where
-
-</haskell>
-
-And then import the necessary libraries:
-
-<haskell>
-
-> import System.IO
-> import Control.Monad
-> import Text.ParserCombinators.Parsec
-> import Text.ParserCombinators.Parsec.Expr
-> import Text.ParserCombinators.Parsec.Language
-> import qualified Text.ParserCombinators.Parsec.Token as Token
-
-</haskell>
-
-== The language ==
-
-The grammar for expressions is defined as follows:
-
-<tt>
-
-''a''   ::=  ''x'' | ''n'' | - ''a'' | ''a'' ''opa'' ''a''
-
-''b''   ::=  true | false | not ''b'' | ''b'' ''opb'' ''b'' | ''a'' ''opr'' ''a''
-
-''opa'' ::=  + | - | * | /
-
-''opb'' ::=  and | or
-
-''opr'' ::=  > | <
-
-</tt>
-
-Note that we have three groups of operators - arithmetic, booloan and
-relational ones.
-
-And now the definition of statements:
-
-<tt>
-
-''S''   ::=  x := ''a'' | skip | ''S1''; ''S2'' | ''( S )'' | if ''b'' then ''S1'' else ''S2'' | while ''b'' do ''S''
-
-</tt>
-
-We probably want to parse that into some internal representation of the
-language (abstract syntax tree). Therefore we need to define the data
-structures for the expressions and statements.
-
-== Data structures ==
-
-We need to take care of boolean and arithmetic expressions and the
-appropriate operators. First let's look at the boolean expressions:
-
-<haskell>
-
-> data BExpr = BConst Bool
->            | Not BExpr
->            | And BExpr BExpr
->            | Greater AExpr AExpr
->             deriving (Show, Eq)
-
-</haskell>
-
-Now we define the types for arithmetic expressions:
-
-<haskell>
-
-> data AExpr = Var String
->            | Const Integer
->            | Neg AExpr
->            | Add AExpr AExpr
->              deriving (Show, Eq)
-
-</haskell>
-
-Finally let's take care of the statements:
-
-<haskell>
-
-> data Stmt = Seq [Stmt]
->           | Assign String AExpr
->           | If BExpr Stmt Stmt
->           | While BExpr Stmt
->           | Skip
->             deriving (Show, Eq)
-
-</haskell>
-
-== Lexer ==
-
-Having all the data structures we can go on with writing the code to do actual
-parsing. First of all we create the language definition using Haskell's record
-syntax and the constructor <hask>emptyDef</hask> (from
-<hask>Text.ParserCombinators.Parsec.Language</hask>):
-
-<haskell>
-
-> languageDef =
->   emptyDef { Token.commentStart    = "/*"
->            , Token.commentEnd      = "*/"
->            , Token.commentLine     = "//"
->            , Token.identStart      = letter
->            , Token.identLetter     = alphaNum
->            , Token.reservedNames   = [ "if"
->                                      , "then"
->                                      , "else"
->                                      , "while"
->                                      , "do"
->                                      , "skip"
->                                      , "true"
->                                      , "false"
->                                      , "not"
->                                      , "and"
->                                      , "or"
->                                      ]
->            , Token.reservedOpNames = ["+", "-", "*", "/", ":="
->                                      , "<", ">", "and", "or", "not"
->                                      ]
->            }
-
-</haskell>
-
-This creates a language definition that accepts the C-style comments, requires
-that the identifiers start with a letter, and end with alphanumeric
-characters. Moreover there is a number of reserved names, that cannot be used
-by the identifiers.
-
-Having the above definition we can create a lexer:
-
-<haskell>
-
-> lexer = Token.makeTokenParser languageDef
-
-</haskell>
-
-<tt>lexer</tt> contains a number of lexical parsers, that we can us to parse
-identifiers, reserved words/operations, etc. Now we can select/extract them in
-the following way:
-
-<haskell>
-
-> identifier = Token.identifier lexer -- parses an identifier
-> reserved   = Token.reserved   lexer -- parses a reserved name
-> reservedOp = Token.reservedOp lexer -- parses an operator
-> parens     = Token.parens     lexer -- parses surrounding parenthesis:
->                                     --   parens p
->                                     -- takes care of the parenthesis and
->                                     -- uses p to parse what's inside them
-> integer    = Token.integer    lexer -- parses an integer
-> semi       = Token.semi       lexer -- parses a semicolon
-> whiteSpace = Token.whiteSpace lexer -- parses whitespace
-
-</haskell>
-
-This isn't really necessary, but should make the code much more readable (also
-this is the reason why we used the qualified import of
-<hask>Text.ParserCombinators.Parsec.Token</hask>). Now we can use them to
-parse the source code at the token level. One of the nice features of these
-parsers is that they take care of all whitespace after the tokens.
-
-== Main parser ==
-
-As already mentioned a program in this language is simply a statement, so the
-main parser should basically only parse a statement. But remember to take care of
-initial whitespace - our parsers only get rid of whitespace after the tokens!
-
-<haskell>
-
-> whileParser :: Parser Stmt
-> whileParser = whiteSpace >> statement
-
-</haskell>
-
-Now because any statement might be actually a sequence of statements separated
-by semicolon, we use <hask>sepBy1</hask> to parse at least one statement. The
-result is a list of statements. We also allow grouping statements by the
-parenthesis, which is useful, for instance, in the <tt>while</tt> loop.
-
-<haskell>
-
-> statement :: Parser Stmt
-> statement =   parens statement
->           <|> sequenceOfStmt
-
-> sequenceOfStmt =
->   do list <- (sepBy1 statement' semi)
->      -- If there's only one statement return it without using Seq.
->      return $ if length list == 1 then head list else Seq list
-
-</haskell>
-
-Now a single statement is quite simple, it's either an if conditional, a while
-loop, an assignment or simply a skip statement. We use <hask><|></hask> to
-express choice. So <hask>a <|> b</hask> will first try parser <hask>a</hask>
-and if it fails (but without actually consuming any input) then parser
-<hask>b</hask> will be used. Note: this means that the order is important.
-
-<haskell>
-
-> statement' :: Parser Stmt
-> statement' =   ifStmt
->            <|> whileStmt
->            <|> skipStmt
->            <|> assignStmt
-
-</haskell>
-
-If you have a parser that might fail after consuming some input, and you still
-want to try the next parser, you should look into <hask>try</hask> combinator.
-For instance <hask>try p <|> q</hask> will try parsing with <hask>p</hask> and
-if it fails, even after consuming the input, the <hask>q</hask> parser will be
-used as if nothing has been consumed by <hask>p</hask>.
-
-Now let's define the parsers for all the possible statements. This is quite
-straightforward as we just use the parsers from the lexer and then use all the
-necessary information to create appropriate data structures.
-
-<haskell>
-
-> ifStmt :: Parser Stmt
-> ifStmt =
->   do reserved "if"
->      cond  <- bExpression
->      reserved "then"
->      stmt1 <- statement
->      reserved "else"
->      stmt2 <- statement
->      return $ If cond stmt1 stmt2
-
-> whileStmt :: Parser Stmt
-> whileStmt =
->   do reserved "while"
->      cond <- bExpression
->      reserved "do"
->      stmt <- statement
->      return $ While cond stmt
-
-> assignStmt :: Parser Stmt
-> assignStmt =
->   do var  <- identifier
->      reservedOp ":="
->      expr <- aExpression
->      return $ Assign var expr
-
-> skipStmt :: Parser Stmt
-> skipStmt = reserved "skip" >> return Skip
-
-</haskell>
-
-== Expressions ==
-
-What's left is to parse the expressions. Fortunately Parsec provides a very
-easy way to do that. Let's define the arithmetic and boolean expressions:
-
-<haskell>
-
-> aExpression :: Parser AExpr
-> aExpression = buildExpressionParser aOperators aTerm
-
-> bExpression :: Parser BExpr
-> bExpression = buildExpressionParser bOperators bTerm
-
-</haskell>
-
-Now we have to define the lists with operator precedence, associativity and
-what constructors to use in each case.
-
-<haskell>
-
-> aOperators = [ [Prefix (reservedOp "-"   >> return (Neg             ))          ]
->              , [Infix  (reservedOp "+"   >> return (Add             )) AssocLeft]
->               ]
-
-> bOperators = [ [Prefix (reservedOp "not" >> return (Not             ))          ]
->              , [Infix  (reservedOp "and" >> return (And             )) AssocLeft]
->              ]
-
-</haskell>
-
-In case of Prefix operators it is enough to specify which one should be parsed
-and what is the associated data constructor. Infix operators are defined
-similarly, but it's necessary to add information about associativity. Note
-that the operator precedence depends only on the order of the elements in the
-list.
-
-Finally we have to define the terms. In case of arithmetic expressions, it is
-quite simple:
-
-<haskell>
-
-> aTerm =  parens aExpression
->      <|> liftM Var identifier
->      <|> liftM Const integer
-
-</haskell>
-
-However, the term in a boolean expression is a bit more tricky. In this case,
-a term can also be an expression with relational operator consisting of
-arithmetic expressions.
-
-<haskell>
-
-> bTerm =  parens bExpression
->      <|> (reserved "true"  >> return (BConst True ))
->      <|> (reserved "false" >> return (BConst False))
->      <|> rExpression
-
-</haskell>
-
-Therefore we have to define a parser for relational expressions:
-
-<haskell>
-
-> rExpression =
->   do a1 <- aExpression
->      op <- reservedOp ">"
->      a2 <- aExpression
->      return $ Greater a1 a2
-
-</haskell>
-
-And that's it. We have a quite simple parser able to parse a few statements and
-arithmetic/boolean expressions.
-
-== Notes ==
-
-If you want to experiment with the parser inside ghci, these functions might be
-handy:
-
-<haskell>
-
-> parseString :: String -> Stmt
-> parseString str =
->   case parse whileParser "" str of
->     Left e  -> error $ show e
->     Right r -> r
-
-> parseFile :: String -> IO Stmt
-> parseFile file =
->   do program  <- readFile file
->      case parse whileParser "" program of
->        Left e  -> print e >> fail "parse error"
->        Right r -> return r
-
-</haskell>
-
-Now you can simply load the module in ghci and then do
-<hask>ast <- parseFile "<filename>"</hask> to parse a file and get the
-result if parsing was successful. If you already have a string with
-the program, you can use <hask>parseString</hask>.
-
+Source: http://www.haskell.org/haskellwiki/Parsing_a_simple_imperative_language
+
+This tutorial will present how to parse a subset of a simple imperative
+programming language called W<small>HILE</small> (introduced in a book
+"Principles of Program Analysis" by Nielson, Nielson and Hankin). It includes
+only a few statements and basic boolean/arithmetic expressions, which makes it
+a nice material for a tutorial.
+
+== Imports ==
+
+First let's specify the name of the module:
+
+<haskell>
+
+> module Lang where
+
+</haskell>
+
+And then import the necessary libraries:
+
+<haskell>
+
+> import System.IO
+> import Control.Monad
+> import Text.ParserCombinators.Parsec
+> import Text.ParserCombinators.Parsec.Expr
+> import Text.ParserCombinators.Parsec.Language
+> import qualified Text.ParserCombinators.Parsec.Token as Token
+
+</haskell>
+
+== The language ==
+
+The grammar for expressions is defined as follows:
+
+<tt>
+
+''a''   ::=  ''x'' | ''n'' | - ''a'' | ''a'' ''opa'' ''a''
+
+''b''   ::=  true | false | not ''b'' | ''b'' ''opb'' ''b'' | ''a'' ''opr'' ''a''
+
+''opa'' ::=  + | - | * | /
+
+''opb'' ::=  and | or
+
+''opr'' ::=  > | <
+
+</tt>
+
+Note that we have three groups of operators - arithmetic, booloan and
+relational ones.
+
+And now the definition of statements:
+
+<tt>
+
+''S''   ::=  x := ''a'' | skip | ''S1''; ''S2'' | ''( S )'' | if ''b'' then ''S1'' else ''S2'' | while ''b'' do ''S''
+
+</tt>
+
+We probably want to parse that into some internal representation of the
+language (abstract syntax tree). Therefore we need to define the data
+structures for the expressions and statements.
+
+== Data structures ==
+
+We need to take care of boolean and arithmetic expressions and the
+appropriate operators. First let's look at the boolean expressions:
+
+<haskell>
+
+> data BExpr = BConst Bool
+>            | Not BExpr
+>            | And BExpr BExpr
+>            | Greater AExpr AExpr
+>             deriving (Show, Eq)
+
+</haskell>
+
+Now we define the types for arithmetic expressions:
+
+<haskell>
+
+> data AExpr = Var String
+>            | Const Integer
+>            | Neg AExpr
+>            | Add AExpr AExpr
+>              deriving (Show, Eq)
+
+</haskell>
+
+Finally let's take care of the statements:
+
+<haskell>
+
+> data Stmt = Seq [Stmt]
+>           | Assign String AExpr
+>           | If BExpr Stmt Stmt
+>           | While BExpr Stmt
+>           | Skip
+>             deriving (Show, Eq)
+
+</haskell>
+
+== Lexer ==
+
+Having all the data structures we can go on with writing the code to do actual
+parsing. First of all we create the language definition using Haskell's record
+syntax and the constructor <hask>emptyDef</hask> (from
+<hask>Text.ParserCombinators.Parsec.Language</hask>):
+
+<haskell>
+
+> languageDef =
+>   emptyDef { Token.commentStart    = "/*"
+>            , Token.commentEnd      = "*/"
+>            , Token.commentLine     = "//"
+>            , Token.identStart      = letter
+>            , Token.identLetter     = alphaNum
+>            , Token.reservedNames   = [ "if"
+>                                      , "then"
+>                                      , "else"
+>                                      , "while"
+>                                      , "do"
+>                                      , "skip"
+>                                      , "true"
+>                                      , "false"
+>                                      , "not"
+>                                      , "and"
+>                                      , "or"
+>                                      ]
+>            , Token.reservedOpNames = ["+", "-", "*", "/", ":="
+>                                      , "<", ">", "and", "or", "not"
+>                                      ]
+>            }
+
+</haskell>
+
+This creates a language definition that accepts the C-style comments, requires
+that the identifiers start with a letter, and end with alphanumeric
+characters. Moreover there is a number of reserved names, that cannot be used
+by the identifiers.
+
+Having the above definition we can create a lexer:
+
+<haskell>
+
+> lexer = Token.makeTokenParser languageDef
+
+</haskell>
+
+<tt>lexer</tt> contains a number of lexical parsers, that we can us to parse
+identifiers, reserved words/operations, etc. Now we can select/extract them in
+the following way:
+
+<haskell>
+
+> identifier = Token.identifier lexer -- parses an identifier
+> reserved   = Token.reserved   lexer -- parses a reserved name
+> reservedOp = Token.reservedOp lexer -- parses an operator
+> parens     = Token.parens     lexer -- parses surrounding parenthesis:
+>                                     --   parens p
+>                                     -- takes care of the parenthesis and
+>                                     -- uses p to parse what's inside them
+> integer    = Token.integer    lexer -- parses an integer
+> semi       = Token.semi       lexer -- parses a semicolon
+> whiteSpace = Token.whiteSpace lexer -- parses whitespace
+
+</haskell>
+
+This isn't really necessary, but should make the code much more readable (also
+this is the reason why we used the qualified import of
+<hask>Text.ParserCombinators.Parsec.Token</hask>). Now we can use them to
+parse the source code at the token level. One of the nice features of these
+parsers is that they take care of all whitespace after the tokens.
+
+== Main parser ==
+
+As already mentioned a program in this language is simply a statement, so the
+main parser should basically only parse a statement. But remember to take care of
+initial whitespace - our parsers only get rid of whitespace after the tokens!
+
+<haskell>
+
+> whileParser :: Parser Stmt
+> whileParser = whiteSpace >> statement
+
+</haskell>
+
+Now because any statement might be actually a sequence of statements separated
+by semicolon, we use <hask>sepBy1</hask> to parse at least one statement. The
+result is a list of statements. We also allow grouping statements by the
+parenthesis, which is useful, for instance, in the <tt>while</tt> loop.
+
+<haskell>
+
+> statement :: Parser Stmt
+> statement =   parens statement
+>           <|> sequenceOfStmt
+
+> sequenceOfStmt =
+>   do list <- (sepBy1 statement' semi)
+>      -- If there's only one statement return it without using Seq.
+>      return $ if length list == 1 then head list else Seq list
+
+</haskell>
+
+Now a single statement is quite simple, it's either an if conditional, a while
+loop, an assignment or simply a skip statement. We use <hask><|></hask> to
+express choice. So <hask>a <|> b</hask> will first try parser <hask>a</hask>
+and if it fails (but without actually consuming any input) then parser
+<hask>b</hask> will be used. Note: this means that the order is important.
+
+<haskell>
+
+> statement' :: Parser Stmt
+> statement' =   ifStmt
+>            <|> whileStmt
+>            <|> skipStmt
+>            <|> assignStmt
+
+</haskell>
+
+If you have a parser that might fail after consuming some input, and you still
+want to try the next parser, you should look into <hask>try</hask> combinator.
+For instance <hask>try p <|> q</hask> will try parsing with <hask>p</hask> and
+if it fails, even after consuming the input, the <hask>q</hask> parser will be
+used as if nothing has been consumed by <hask>p</hask>.
+
+Now let's define the parsers for all the possible statements. This is quite
+straightforward as we just use the parsers from the lexer and then use all the
+necessary information to create appropriate data structures.
+
+<haskell>
+
+> ifStmt :: Parser Stmt
+> ifStmt =
+>   do reserved "if"
+>      cond  <- bExpression
+>      reserved "then"
+>      stmt1 <- statement
+>      reserved "else"
+>      stmt2 <- statement
+>      return $ If cond stmt1 stmt2
+
+> whileStmt :: Parser Stmt
+> whileStmt =
+>   do reserved "while"
+>      cond <- bExpression
+>      reserved "do"
+>      stmt <- statement
+>      return $ While cond stmt
+
+> assignStmt :: Parser Stmt
+> assignStmt =
+>   do var  <- identifier
+>      reservedOp ":="
+>      expr <- aExpression
+>      return $ Assign var expr
+
+> skipStmt :: Parser Stmt
+> skipStmt = reserved "skip" >> return Skip
+
+</haskell>
+
+== Expressions ==
+
+What's left is to parse the expressions. Fortunately Parsec provides a very
+easy way to do that. Let's define the arithmetic and boolean expressions:
+
+<haskell>
+
+> aExpression :: Parser AExpr
+> aExpression = buildExpressionParser aOperators aTerm
+
+> bExpression :: Parser BExpr
+> bExpression = buildExpressionParser bOperators bTerm
+
+</haskell>
+
+Now we have to define the lists with operator precedence, associativity and
+what constructors to use in each case.
+
+<haskell>
+
+> aOperators = [ [Prefix (reservedOp "-"   >> return (Neg             ))          ]
+>              , [Infix  (reservedOp "+"   >> return (Add             )) AssocLeft]
+>               ]
+
+> bOperators = [ [Prefix (reservedOp "not" >> return (Not             ))          ]
+>              , [Infix  (reservedOp "and" >> return (And             )) AssocLeft]
+>              ]
+
+</haskell>
+
+In case of Prefix operators it is enough to specify which one should be parsed
+and what is the associated data constructor. Infix operators are defined
+similarly, but it's necessary to add information about associativity. Note
+that the operator precedence depends only on the order of the elements in the
+list.
+
+Finally we have to define the terms. In case of arithmetic expressions, it is
+quite simple:
+
+<haskell>
+
+> aTerm =  parens aExpression
+>      <|> liftM Var identifier
+>      <|> liftM Const integer
+
+</haskell>
+
+However, the term in a boolean expression is a bit more tricky. In this case,
+a term can also be an expression with relational operator consisting of
+arithmetic expressions.
+
+<haskell>
+
+> bTerm =  parens bExpression
+>      <|> (reserved "true"  >> return (BConst True ))
+>      <|> (reserved "false" >> return (BConst False))
+>      <|> rExpression
+
+</haskell>
+
+Therefore we have to define a parser for relational expressions:
+
+<haskell>
+
+> rExpression =
+>   do a1 <- aExpression
+>      op <- reservedOp ">"
+>      a2 <- aExpression
+>      return $ Greater a1 a2
+
+</haskell>
+
+And that's it. We have a quite simple parser able to parse a few statements and
+arithmetic/boolean expressions.
+
+== Notes ==
+
+If you want to experiment with the parser inside ghci, these functions might be
+handy:
+
+<haskell>
+
+> parseString :: String -> Stmt
+> parseString str =
+>   case parse whileParser "" str of
+>     Left e  -> error $ show e
+>     Right r -> r
+
+> parseFile :: String -> IO Stmt
+> parseFile file =
+>   do program  <- readFile file
+>      case parse whileParser "" program of
+>        Left e  -> print e >> fail "parse error"
+>        Right r -> return r
+
+</haskell>
+
+Now you can simply load the module in ghci and then do
+<hask>ast <- parseFile "<filename>"</hask> to parse a file and get the
+result if parsing was successful. If you already have a string with
+the program, you can use <hask>parseString</hask>.
+
 [[Category:How to]]
diff --git a/examples/MultiRec.hs b/examples/MultiRec.hs
--- a/examples/MultiRec.hs
+++ b/examples/MultiRec.hs
@@ -1,129 +1,120 @@
-{-# LANGUAGE GADTs                 #-}
-{-# LANGUAGE KindSignatures        #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE TypeOperators         #-}
-{-# LANGUAGE TypeSynonymInstances  #-}
-{-# LANGUAGE EmptyDataDecls        #-}
-{-# LANGUAGE TemplateHaskell       #-}
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE DataKinds             #-}
-{-# LANGUAGE PolyKinds             #-}
-{-# LANGUAGE TypeFamilies          #-}
-{-# LANGUAGE StandaloneDeriving    #-}
-
-module MultiRec where
-
-import Datatypes
-import Generics.MultiRec.Any
-import Generics.MultiRec.Transformations.RewriteRules as RR
-import Generics.MultiRec.Transformations.ZipperState
-import Generics.MultiRec.Transformations.Explicit as Ex
-import Generics.MultiRec.Transformations.TH
-import Generics.MultiRec.Rewriting
-import Generics.MultiRec.Zipper
-
-import Generics.MultiRec hiding (show)
-import Generics.MultiRec.TH
-
-import Control.Monad ( (>=>) )
-
---------------------------------------------------------------------------------
--- Multirec representations for the example datatypes
---------------------------------------------------------------------------------
-data TreeAST :: * -> * where
-  Tree :: TreeAST Tree
-
-$(deriveAll ''TreeAST)
-
-data ListAST :: * -> * -> * where
-  List :: ListAST a (List a)
-
-$(deriveAll ''ListAST)
-
-data XAST :: * -> * where
-  X :: XAST X
-
-$(deriveAll ''XAST)
-
-data ZigZag :: * -> * where
-  Zig :: ZigZag Zig
-  Zag :: ZigZag Zag
-
-$(deriveAll ''ZigZag)
-
-data AST i where
-  BExpr  :: AST BExpr
-  AExpr  :: AST AExpr
-  Stmt   :: AST Stmt
-
-$(deriveAll ''AST)
-
---------------------------------------------------------------------------------
--- Rewrite rules solution
---------------------------------------------------------------------------------
-instance RR.Transform AST
-
--- Now we can simply do the above transformation in a nice way!
-rr = RR.apply [insert (down >=> right >=> right) change] Stmt prog1 == Just prog2
-  where
-    change = rule $ \e a b -> If e a b :~> If (Not e) b a
-
--- The same one in two steps, which illustrates that rules can be of different
--- types
-rr2 = RR.apply [ insert (down >=> right >=> right) swap
-               , insert down addNot] Stmt prog1          == Just prog2
-  where
-    swap   :: Rule AST Stmt
-    swap   = rule $ \e a b -> If e a b :~> If e b a
-    addNot :: Rule AST BExpr
-    addNot = rule $ \e -> e :~> Not e
-
---------------------------------------------------------------------------------
--- Zipper with state
---------------------------------------------------------------------------------
-zs = navigate Stmt prog1 $ do
-  downMonad >> rightMonad >> rightMonad
-  -- Swap
-  l <- downMonad >> rightMonad
-  r <- rightMonad
-  updateMonad (\p _ -> matchAny p l)
-  leftMonad
-  updateMonad (\p _ -> matchAny p r)
-  -- Add the not
-  leftMonad
-  updateMonad (\p e -> case p of
-                  BExpr -> Just (Not e)
-                  _     -> Nothing)
-
---------------------------------------------------------------------------------
--- Explicit
---------------------------------------------------------------------------------
-instance Ex.Transform AST
-
--- Ordering index of AST as AExpr < BExpr < Stmt
-instance OrdI AST where
-  indexI AExpr = 0
-  indexI BExpr = 1
-  indexI Stmt  = 2
-
-$(deriveRefRep ''AST (postfix "EH"))
-deriving instance Show AExprEH
-deriving instance Show BExprEH
-deriving instance Show StmtEH
-
--- Show existentials
-instance Show (NiceInsert AST) where
-  show (NiceInsert AExpr x l) = "NiceInsert AExpr " ++ show x ++ " (" ++ show l ++ ")"
-  show (NiceInsert BExpr x l) = "NiceInsert BExpr " ++ show x ++ " (" ++ show l ++ ")"
-  show (NiceInsert Stmt x l)  = "NiceInsert Stmt " ++ show x ++ " (" ++ show l ++ ")"
-
--- Actual example
-{- This prints: (note the different reference types here)
-  [ NiceInsert BExpr [2,0] (NotEH (RefBExpr [2,0]))
-  , NiceInsert Stmt [2,1] (RefStmt [2,2])
-  , NiceInsert Stmt [2,2] (RefStmt [2,1]) ]
--}
-expl1 = print $ toNiceTransformation $ diff Stmt prog1 prog2
-expl2 = print $ toNiceTransformation $ diff Stmt prog3 prog4
-expl3 = print $ toNiceTransformation $ diff Stmt prog5 prog6
+{-# LANGUAGE GADTs                 #-}
+{-# LANGUAGE KindSignatures        #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE TypeOperators         #-}
+{-# LANGUAGE TypeSynonymInstances  #-}
+{-# LANGUAGE EmptyDataDecls        #-}
+{-# LANGUAGE TemplateHaskell       #-}
+{-# LANGUAGE FlexibleInstances     #-}
+{-# LANGUAGE DataKinds             #-}
+{-# LANGUAGE PolyKinds             #-}
+{-# LANGUAGE TypeFamilies          #-}
+{-# LANGUAGE StandaloneDeriving    #-}
+{-# LANGUAGE PatternSynonyms       #-}
+{-# LANGUAGE ScopedTypeVariables   #-}
+{-# LANGUAGE RankNTypes            #-}
+
+module MultiRec where
+
+import Datatypes
+import Generics.MultiRec.Transformations.Main
+import Generics.MultiRec.Transformations.Path
+
+import Generics.MultiRec hiding ( show )
+import Generics.MultiRec.TH
+
+import Control.Monad ( (>=>) )
+
+--------------------------------------------------------------------------------
+-- Multirec representations for the example datatypes
+--------------------------------------------------------------------------------
+data TreeAST :: * -> * where
+  Tree :: TreeAST Tree
+
+$(deriveAll ''TreeAST)
+
+data ListAST :: * -> * -> * where
+  List :: ListAST a (List a)
+
+$(deriveAll ''ListAST)
+
+data XAST :: * -> * where
+  X :: XAST X
+
+$(deriveAll ''XAST)
+
+data ZigZag :: * -> * where
+  Zig :: ZigZag Zig
+  Zag :: ZigZag Zag
+
+$(deriveAll ''ZigZag)
+
+data AST i where
+  BExpr  :: AST BExpr
+  AExpr  :: AST AExpr
+  Stmt   :: AST Stmt
+
+$(deriveAll ''AST)
+
+--------------------------------------------------------------------------------
+-- Examples
+--------------------------------------------------------------------------------
+
+type instance Ixs AST = '[ AExpr, BExpr, Stmt ]
+
+deriving instance Ord AExpr
+deriving instance Ord BExpr
+deriving instance Ord Stmt
+
+test1 :: Transformation AST Stmt
+test1 = diff Stmt prog1 prog2
+
+-- Constructor pattern synonyms
+pattern Ref' :: Path phi ix top -> HWithRef phi top ix
+pattern Ref' x = HIn (Ref x)
+
+pattern Const' :: forall top. Integer -> HWithRef AST top AExpr
+pattern Const' i = HIn (InR (R (L (Tag (R (L (C (K i))))))))
+
+pattern BConst' :: forall top. Bool -> HWithRef AST top BExpr
+pattern BConst' b = HIn (InR (L (Tag (L (C (K b))))))
+
+pattern And' :: forall top. HWithRef AST top BExpr -> HWithRef AST top BExpr
+             -> HWithRef AST top BExpr
+pattern And' b1 b2 = HIn (InR (L (Tag (R (R (L (C (I b1 :*: I b2))))))))
+
+pattern GT' :: forall top. HWithRef AST top AExpr -> HWithRef AST top AExpr
+            -> HWithRef AST top BExpr
+pattern GT' a1 a2 = HIn (InR (L (Tag (R (R (R (C (I a1 :*: I a2))))))))
+
+test2 :: HWithRef AST top BExpr
+test2 = BConst' True
+
+test3 :: HWithRef AST top BExpr
+test3 = And' test2 test2
+
+-- test6 :: HWithRef AST BExpr BExpr
+-- test6 = And' (GT' (Ref' test7) (Const' 2)) (Ref' test4)
+
+-- Path pattern synonyms
+pattern End     = Empty
+pattern Not_0 p = Push BExpr (CL (CTag (CR (CL (CC CId))))) p
+
+pattern GT_0 :: Path AST top AExpr -> Path AST top BExpr
+pattern GT_0  p = Push AExpr (CL (CTag (CR (CR (CR (CC (C1 CId (I (K0 ()))))))))) p
+
+pattern Neg_0 :: Path AST top AExpr -> Path AST top AExpr
+pattern Neg_0 p = Push AExpr (CR (CL (CTag (CR (CR (CL (CC CId))))))) p
+
+test4 :: Path AST BExpr BExpr
+test4 = Not_0 (Not_0 End)
+
+test5 :: Path AST AExpr BExpr
+test5 = Not_0 (GT_0 End)
+
+test7 :: Path AST AExpr AExpr
+test7 = Neg_0 End
+
+--
+testPrgm = diff Stmt prog1 prog2
diff --git a/examples/Regular.hs b/examples/Regular.hs
--- a/examples/Regular.hs
+++ b/examples/Regular.hs
@@ -1,212 +1,118 @@
-{-# LANGUAGE FlexibleInstances  #-}
-{-# LANGUAGE FlexibleContexts   #-}
-{-# LANGUAGE TypeFamilies       #-}
-{-# LANGUAGE TemplateHaskell    #-}
-{-# LANGUAGE TypeOperators      #-}
-{-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE EmptyDataDecls     #-}
-module Regular where
-
-import Datatypes
-import Generics.Regular hiding (right)
-import Generics.Regular.Transformations.Explicit as Ex
-import Generics.Regular.Transformations.RewriteRules as RR
-import Generics.Regular.Zipper
-import Generics.Regular.Transformations.ZipperState
-import Generics.Regular.Transformations.TH
-
-import Control.Monad ( (>=>) )
-import Generics.Regular.Rewriting hiding (left, right)
-import Data.Maybe (fromJust)
-
---------------------------------------------------------------------------------
--- Regular representations for the example datatypes
---------------------------------------------------------------------------------
---Trees
-$(deriveAll ''Tree "PFTree")
-type instance PF Tree = PFTree
-
--- Lists
-$(deriveAll ''List "PFL")
-type instance PF (List a) = PFL a
-
--- Something more exotic
-$(deriveAll ''X "PFX")
-type instance PF X = PFX
-
--- Example for paper (do manual instance to avoid C's)
-type instance PF Expr = K String :+: K Integer :+: I :+: I :*: I
-
-instance Regular Expr where
-  from  (Var s)       = L (K s)
-  from  (Const i)     = R (L (K i))
-  from  (Neg e)       = R (R (L (I e)))
-  from  (Add e1 e2)   = R (R (R (I e1 :*: I e2)))
-
-  to (L (K s))                    = Var s
-  to (R (L (K i)))                = Const i
-  to (R (R (L (I e))))            = Neg e
-  to (R (R (R (I e1 :*: I e2))))  = Add e1 e2
-
-
---------------------------------------------------------------------------------
--- Examples for the paper
---------------------------------------------------------------------------------
--- Some example values
-expr1 :: Expr
-expr1 = Add (Const 1) (Var "a")
-
-expr2 :: Expr
-expr2 = Add (Const 1) (Neg (Var "a"))
-
-expr3 :: Expr
-expr3 = Add (Var "a") (Const 1)
-
-instance RR.Transform Expr
-instance Ex.Transform Expr
-
-instance Show (Fix (WithRef Expr)) where
-  show (In (Ref p)) = "Ref " ++ show p
-
--- Insertion (expr1 => expr2)
-rewriteRulesIns :: Maybe Expr
-rewriteRulesIns = RR.apply [(down >=> right, rule1)] expr1
-  where rule1 :: Rule Expr
-        rule1 = rule $ \x -> x :~> Neg x
-
-zipperStateIns :: Maybe Expr
-zipperStateIns = navigate expr1 $ do
-  downMonad >> rightMonad
-  updateMonad Neg
-
-explicitIns :: Maybe Expr
-explicitIns = Ex.apply addNeg expr1
-  where addNeg :: Ex.Transformation Expr
-        addNeg = [ ([1], In . InR . R . R . L . I . In $ Ref [1]) ]
-
--- Deletion (expr2 => expr1)
-
-rewriteRulesDel :: Maybe Expr
-rewriteRulesDel = RR.apply [(down >=> right, rule2)] expr2
-  where rule2 :: Rule Expr
-        rule2 = rule $ \x -> Neg x :~> x
-
-zipperStateDel :: Maybe Expr
-zipperStateDel = navigate expr2 $ do
-  r <- downMonad >> rightMonad >> downMonad
-  upMonad
-  updateMonad (const r)
-
-explicitDel :: Maybe Expr
-explicitDel = Ex.apply delNeg expr2
-  where delNeg :: Ex.Transformation Expr
-        delNeg = [ ([1], In (Ref [1,0])) ]
-
--- Swapping (expr1 => expr3)
-rewriteRulesSwap :: Maybe Expr
-rewriteRulesSwap = RR.apply [(return, rule3)] expr1
-  where rule3 :: Rule Expr
-        rule3 = rule $ \l r -> Add l r :~> Add r l
-
-zipperStateSwap :: Maybe Expr
-zipperStateSwap = navigate expr1 $ do
-  l <- downMonad
-  r <- rightMonad
-  updateMonad (const l)
-  leftMonad
-  updateMonad (const r)
-
-explicitSwap :: Maybe Expr
-explicitSwap = Ex.apply swap' expr1
-  where swap' :: Ex.Transformation Expr
-        swap' = [ ([0], In $ Ref [1]) 
-                , ([1], In $ Ref [0])]
-
--- Rotation
-rotate1 = Add (Var "a") (Add (Var "b") (Var "c"))
-rotate2 = Add (Add (Var "a") (Var "b")) (Var "c")
-rotate = diff rotate1 rotate2
-
---------------------------------------------------------------------------------
--- Other RewriteRules examples
---------------------------------------------------------------------------------
-instance RR.Transform Tree
-instance RR.Transform X
-
--- Test swapping two subtrees. Note the nice syntax!
-swap :: Rule Tree
-swap = rule $ \t1 t2 -> Bin t1 t2 :~> Bin t2 t1
-
-t1 = RR.apply [(return        , swap)]      exTree4
-t2 = RR.apply [(down          , swap)]      exTree4
-t3 = RR.apply [(down >=> right, swap)]      exTree4
-t4 = RR.apply [(down >=> right, swap), (return, swap)] exTree4 -- == id
-
--- A tricky example
-ruleSwapC, ruleAddB :: Rule X
-ruleSwapC = rule $ \x y -> XC x y :~> XC y x
-ruleAddB  = rule $ \x   -> XA x   :~> XA (XB x)
-
-t6 = RR.apply [(down >=> down >=> down, ruleSwapC)] exX1
-t7 = RR.apply [(down >=> down,          ruleAddB)]  (fromJust t6)
-t8 = RR.apply [(return,                 ruleAddB)]  (fromJust t7)
-t9 = t8 == Just exX2 -- True
-
---------------------------------------------------------------------------------
--- Other ZipperState examples
---------------------------------------------------------------------------------
--- An example using a zipper with state
-t5 = navigate exTree4 $
-       do downMonad >> downMonad
-          saveMonad
-          upMonad >> rightMonad >> downMonad >> rightMonad
-          saveMonad
-          x1 <- loadMonad
-          updateMonad (const x1)
-          upMonad >> leftMonad >> downMonad
-          x2 <- loadMonad
-          updateMonad (const x2)
-
---------------------------------------------------------------------------------
--- A nicer interface for Expr, could be generated using Template Haskell
---------------------------------------------------------------------------------
-data ExprEH
-  = VarEH String
-  | ConstEH Integer
-  | NegEH ExprEH
-  | AddEH ExprEH ExprEH
-  | RefEH Path
-  deriving Show
-
-instance HasRef Expr where
-  type RefRep Expr = ExprEH
-  
-  toRef (Ref p)                           = RefEH p
-  toRef (InR (L (K s)))                   = VarEH s
-  toRef (InR (R (L (K i))))               = ConstEH i
-  toRef (InR (R (R (L (I e)))))           = NegEH e
-  toRef (InR (R (R (R (I e1 :*: I e2))))) = AddEH e1 e2
-  
-  fromRef (RefEH p)      = Ref p
-  fromRef (VarEH s)      = InR (L (K s))
-  fromRef (ConstEH i)    = InR (R (L (K i)))
-  fromRef (NegEH e)      = InR (R (R (L (I e))))
-  fromRef (AddEH e1 e2)  = InR (R (R (R (I e1 :*: I e2))))
-
-
-$(deriveRefRep ''Tree (postfix "EH"))
-deriving instance Show TreeEH
-
--- Test
-instance Ex.Transform Tree
-treeSwapNice :: Maybe Tree
-treeSwapNice = Ex.apply (fromNiceTransformation swap) exTree1
-  where swap = [([0],RefTree [1]),([1],RefTree [0])]
-
-treeDiff :: Ex.NiceTransformation Tree
-treeDiff = toNiceTransformation $ Ex.diff exTree3 exTree5
-
-explicitInsNice :: Maybe Expr
-explicitInsNice = Ex.apply (fromNiceTransformation addNeg) expr1
-  where addNeg :: NiceTransformation Expr
-        addNeg = [ ([1], NegEH (RefEH [1])) ]
+{-# LANGUAGE FlexibleInstances  #-}
+{-# LANGUAGE FlexibleContexts   #-}
+{-# LANGUAGE TypeFamilies       #-}
+{-# LANGUAGE TemplateHaskell    #-}
+{-# LANGUAGE TypeOperators      #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE EmptyDataDecls     #-}
+{-# LANGUAGE PatternSynonyms    #-}
+
+module Regular where
+
+import Datatypes
+import Generics.Regular hiding (right)
+import Generics.Regular.Transformations.Main
+import Generics.Regular.Zipper
+
+import Control.Monad ( (>=>) )
+import Data.Maybe (fromJust)
+
+--------------------------------------------------------------------------------
+-- Regular representations for the example datatypes
+--------------------------------------------------------------------------------
+--Trees
+$(deriveAll ''Tree "PFTree")
+type instance PF Tree = PFTree
+
+-- Lists
+$(deriveAll ''List "PFL")
+type instance PF (List a) = PFL a
+
+-- Something more exotic
+$(deriveAll ''X "PFX")
+type instance PF X = PFX
+
+-- Example for paper
+$(deriveAll ''AExpr "PFExpr")
+type instance PF Expr = PFExpr
+
+deriving instance Ord AExpr
+
+-- Datatype patterns
+pattern Var'   x = In (InR (L (C (K x))))
+pattern Const' x = In (InR (R (L (C (K x)))))
+pattern Neg'   x = In (InR (R (R (L (C (I x))))))
+pattern Add' x y = In (InR (R (R (R (C (I x :*: I y))))))
+
+pattern Ref' x  = In (Ref x)
+
+-- Path patterns
+pattern End     = []
+pattern Neg_0 x = CR (CR (CL (CC CId))) : x
+pattern Add_0 x = CR (CR (CR (CC (C1 CId (I ()))))) : x
+pattern Add_1 x = CR (CR (CR (CC (C2 (I ()) CId)))) : x
+
+{-
+type instance PF Expr = K String :+: K Integer :+: I :+: I :*: I
+
+instance Regular Expr where
+  from  (Var s)       = L (K s)
+  from  (Const i)     = R (L (K i))
+  from  (Neg e)       = R (R (L (I e)))
+  from  (Add e1 e2)   = R (R (R (I e1 :*: I e2)))
+
+  to (L (K s))                    = Var s
+  to (R (L (K i)))                = Const i
+  to (R (R (L (I e))))            = Neg e
+  to (R (R (R (I e1 :*: I e2))))  = Add e1 e2
+-}
+
+--------------------------------------------------------------------------------
+-- Examples for the paper
+--------------------------------------------------------------------------------
+instance Transform Expr
+
+-- Some example values
+expr1 :: Expr
+expr1 = Add (Const 1) (Var "a")
+
+expr2 :: Expr
+expr2 = Add (Const 1) (Neg (Var "a"))
+
+expr3 :: Expr
+expr3 = Add (Var "a") (Const 1)
+
+explicitIns :: Maybe Expr
+explicitIns = apply addNeg expr1
+  where addNeg :: Transformation Expr
+        addNeg = diff expr1 expr2
+
+-- Testing the nicer notation for paths and expressions with references
+test1 :: Fix (WithRef Expr)
+test1 = Neg' (Ref' test2)
+
+test2 :: Path Expr
+test2 = Add_1 End
+
+test3 :: Transformation Expr
+test3 = [(test2, test1)]
+
+test4 :: Bool
+test4 = show test3 == show (diff expr1 expr2)
+
+-- Deletion (expr2 => expr1)
+explicitDel :: Maybe Expr
+explicitDel = apply delNeg expr2
+  where delNeg :: Transformation Expr
+        delNeg = diff expr2 expr1 --[ ([1], In (Ref [1,0])) ]
+
+-- Swapping (expr1 => expr3)
+explicitSwap :: Maybe Expr
+explicitSwap = apply swap' expr1
+  where swap' :: Transformation Expr
+        swap' = diff expr1 expr3 -- [ ([0], In $ Ref [1]), ([1], In $ Ref [0])]
+
+-- Rotation
+rotate1 = Add (Var "a") (Add (Var "b") (Var "c"))
+rotate2 = Add (Add (Var "a") (Var "b")) (Var "c")
+rotate = diff rotate1 rotate2
diff --git a/transformations.cabal b/transformations.cabal
--- a/transformations.cabal
+++ b/transformations.cabal
@@ -1,57 +1,144 @@
-name:                transformations
-version:             0.1.1.0
-synopsis:            Generic representation of tree transformations
-description:
-  This library is based on ideas described in the paper:
-  .
-  *  Jeroen Bransen and Jose Pedro Magalhaes.
-     /Generic Representations of Tree Transformations/.
-     WGP'13.
-     <http://dreixel.net/research/pdf/grtt.pdf>
-
-license:             GPL-3
-license-file:        LICENSE
-author:              Jeroen Bransen and Jose Pedro Magalhaes
-maintainer:          generics@haskell.org
--- copyright:           
-category:            Language
-build-type:          Simple
-cabal-version:       >=1.8
-
-
-extra-source-files:    examples/Datatypes.hs
-                       examples/Lang.lhs
-                       examples/Regular.hs
-                       examples/MultiRec.hs
-
-library
-  exposed-modules:
-                       -- Regular part
-                       Generics.Regular.Zipper,
-                       Generics.Regular.Functions.GOrd,
-                       Generics.Regular.Transformations.Explicit,
-                       Generics.Regular.Transformations.TH,
-                       Generics.Regular.Transformations.RewriteRules,
-                       Generics.Regular.Transformations.ZipperState,
-  
-                       -- MultiRec implementation
-                       Generics.MultiRec.Any,
-                       Generics.MultiRec.Ord,
-                       Generics.MultiRec.Transformations.ZipperState,
-                       Generics.MultiRec.Transformations.RewriteRules,
-                       Generics.MultiRec.Transformations.Explicit,
-                       Generics.MultiRec.Transformations.TH,
-
-                       -- Rewriting library for MultiRec
-                       Generics.MultiRec.HZip,
-                       Generics.MultiRec.LR,
-                       Generics.MultiRec.Rewriting,
-                       Generics.MultiRec.Rewriting.Machinery,
-                       Generics.MultiRec.Rewriting.Rules
-
-  -- other-modules:       
-  build-depends:       base >= 4 && < 5, mtl >= 2.1,
-                       regular >= 0.3, rewriting >= 0.2,
-                       multirec >= 0.7.3, zipper >= 0.4.2,
-                       parsec >= 3.1, containers >= 0.1,
-                       template-haskell >= 2.7
+name:                transformations
+version:             0.2.0.0
+synopsis:            Generic representation of tree transformations
+description:
+  This library is based on ideas described in the paper:
+  .
+  *  Jeroen Bransen and Jose Pedro Magalhaes.
+     /Generic Representations of Tree Transformations/.
+     <http://dreixel.net/research/pdf/grtt_jfp_draft.pdf>
+
+license:             GPL-3
+license-file:        LICENSE
+author:              Jeroen Bransen and Jose Pedro Magalhaes
+maintainer:          generics@haskell.org
+-- copyright:
+category:            Language
+build-type:          Simple
+cabal-version:       >=1.8
+
+extra-source-files:    README
+                       QuickCheck.hs
+                       examples/Datatypes.hs
+                       examples/Expr.hs
+                       examples/Lang.lhs
+                       examples/Regular.hs
+                       examples/MultiRec.hs
+                       examples/LUA.hs
+                       examples/LUA_project/application.lua.1
+                       examples/LUA_project/application.lua.2
+                       examples/LUA_project/application.lua.3
+                       examples/LUA_project/application.lua.4
+                       examples/LUA_project/application.lua.5
+                       examples/LUA_project/application.lua.6
+                       examples/LUA_project/application.lua.7
+                       examples/LUA_project/application.lua.8
+                       examples/LUA_project/application.lua.9
+                       examples/LUA_project/application.lua.10
+                       examples/LUA_project/application.lua.11
+                       examples/LUA_project/application.lua.12
+                       examples/LUA_project/application.lua.13
+                       examples/LUA_project/application.lua.14
+                       examples/LUA_project/application.lua.15
+                       examples/LUA_project/application.lua.16
+                       examples/LUA_project/application.lua.17
+                       examples/LUA_project/application.lua.18
+                       examples/LUA_project/application.lua.19
+                       examples/LUA_project/application.lua.20
+                       examples/LUA_project/application.lua.21
+                       examples/LUA_project/application.lua.22
+                       examples/LUA_project/application.lua.23
+                       examples/LUA_project/application.lua.24
+                       examples/LUA_project/application.lua.25
+                       examples/LUA_project/application.lua.26
+                       examples/LUA_project/application.lua.27
+                       examples/LUA_project/application.lua.28
+                       examples/LUA_project/application.lua.29
+                       examples/LUA_project/application.lua.30
+                       examples/LUA_project/application.lua.31
+                       examples/LUA_project/application.lua.32
+                       examples/LUA_project/application.lua.33
+                       examples/LUA_project/application.lua.34
+                       examples/LUA_project/application.lua.35
+                       examples/LUA_project/application.lua.36
+                       examples/LUA_project/application.lua.37
+                       examples/LUA_project/application.lua.38
+                       examples/LUA_project/application.lua.39
+                       examples/LUA_project/application.lua.40
+                       examples/LUA_project/application.lua.41
+                       examples/LUA_project/application.lua.42
+                       examples/LUA_project/application.lua.43
+                       examples/LUA_project/application.lua.44
+                       examples/LUA_project/application.lua.45
+                       examples/LUA_project/application.lua.46
+                       examples/LUA_project/application.lua.47
+                       examples/LUA_project/application.lua.48
+                       examples/LUA_project/application.lua.49
+                       examples/LUA_project/application.lua.50
+                       examples/LUA_project/application.lua.51
+                       examples/LUA_project/application.lua.52
+                       examples/LUA_project/application.lua.53
+                       examples/LUA_project/application.lua.54
+                       examples/LUA_project/application.lua.55
+                       examples/LUA_project/application.lua.56
+                       examples/LUA_project/application.lua.57
+                       examples/LUA_project/application.lua.58
+                       examples/LUA_project/application.lua.59
+                       examples/LUA_project/application.lua.60
+                       examples/LUA_project/application.lua.61
+                       examples/LUA_project/application.lua.62
+                       examples/LUA_project/application.lua.63
+                       examples/LUA_project/application.lua.64
+                       examples/LUA_project/application.lua.65
+                       examples/LUA_project/application.lua.66
+                       examples/LUA_project/application.lua.67
+                       examples/LUA_project/application.lua.68
+                       examples/LUA_project/application.lua.69
+                       examples/LUA_project/application.lua.70
+                       examples/LUA_project/application.lua.71
+                       examples/LUA_project/application.lua.72
+                       examples/LUA_project/application.lua.73
+                       examples/LUA_project/application.lua.74
+                       examples/LUA_project/application.lua.75
+                       examples/LUA_project/application.lua.76
+                       examples/LUA_project/application.lua.77
+                       examples/LUA_project/application.lua.78
+                       examples/LUA_project/application.lua.79
+                       examples/LUA_project/application.lua.80
+                       examples/LUA_project/application.lua.81
+                       examples/LUA_project/application.lua.82
+                       examples/LUA_project/application.lua.83
+                       examples/LUA_project/application.lua.84
+                       examples/LUA_project/application.lua.85
+                       examples/LUA_project/application.lua.86
+                       examples/LUA_project/application.lua.87
+                       examples/LUA_project/application.lua.88
+                       examples/LUA_project/application.lua.89
+                       examples/LUA_project/application.lua.90
+
+library
+  exposed-modules:     Generics.MultiRec.ShallowEq,
+                       Generics.MultiRec.Zipper,
+                       Generics.MultiRec.CountIs,
+
+                       Generics.MultiRec.Transformations.Main,
+                       Generics.MultiRec.Transformations.Path,
+                       Generics.MultiRec.Transformations.MemoTable,
+                       Generics.MultiRec.Transformations.Children,
+                       Generics.MultiRec.Transformations.ZipChildren
+
+                       Generics.Regular.Zipper
+                       Generics.Regular.Functions.GOrd
+                       Generics.Regular.Transformations.Main
+
+  build-depends:       base >= 4.7 && < 5, mtl >= 2.1, regular >= 0.3.4.4,
+                       multirec >= 0.7.3, containers >= 0.1,
+                       template-haskell >= 2.9
+
+executable Benchmark
+  main-is:             QuickCheck.hs
+
+  build-depends:       base >= 4.7 && < 5, mtl >= 2.1,
+                       multirec >= 0.7.3,
+                       parsec >= 3.1, containers >= 0.1,
+                       criterion >= 1, QuickCheck >= 2.7
