diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,2 @@
+Doug Beardsley <mightybyte@gmail.com>
+Ozgun Ataman <oz@soostone.com>
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2013, Doug Beardsley
+Copyright (c) 2013, Soostone Inc
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+Neither the name of the Snap Framework authors nor the names of its
+contributors may be used to endorse or promote products derived from this
+software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,77 @@
+charade
+=======
+
+Haskell program that fills Heist templates with randomly generated data in
+support of rapid UI prototyping.
+
+To see charade in action follow these steps:
+
+1. `git clone https://github.com/Soostone/charade.git`
+1. `cd charade`
+1. `cabal install`
+1. `dist/build/charade/charade`
+1. Point your browser at http://localhost:8000
+1. Look in templates/index.tpl to see how this example works
+
+Charade lets you prototype a site's HTML/CSS/JavaScript using *exactly* the
+Heist template markup that you will have in your final site, without needing
+to write any of the backend code to implement your splices.  Every time you
+use a tag implemented as a Haskell splice, just include the "fake" attribute
+telling charade how to render dummy data for that tag.
+
+Charade decouples the work of designers and backend developers.  A site could
+be started by designers who have a good picture of what they want the
+front-end interface to look like using just a small amount of knowledge about
+splice tags should be structured.  Then developers could be hired to fill in
+the back end.  Alternatively, back end developers could start by developing a
+site's data model and back end.  Then they could hire designers to build the
+look and feel without needing to set up any back end database infrastructure
+or give them an application binary.  This allows designers to work in an
+environment much closer to what will ultimately be used in production.
+
+The charade application is a snap application that serves Heist templates
+and static files.  The charade application allows you to add a "fake"
+attribute anywhere in your HTML to generate fake data in the place of that
+tag.  For instance, in the following paragraph charade will replace the
+\<myParagraph\> tag with a paragraph of lorem ipsum text.  
+
+    <p>
+      <myParagraph fake="lorem"/>
+    </p>
+
+Charade provides the following built-in primitives for generating dummy
+content with the "fake" attribute:
+
+* bool - true/false
+* yesno - yes/no
+* int \<min\> \<max\> - an integer in the interval [min,max]
+* decimal \<min\> \<max\> - a decimal in the interval [min,max]
+* list - a list of 5 copies of its child nodes
+* list \<count\> - a list of \<count\> copies of its child nodes
+* list \<min\> \<max\> - a randomly sized list
+* lorem - a paragraph of lorem ipsum text
+* lorem \<count\> - a paragraph of lorem ipsum text repeated \<count\> times
+* first-name - randomly chosen English first names
+* last-name - randomly chosen English last names
+* enum - arbitrary enumerations specified in a file
+
+The charade application also requires a file "charade.cfg" in the current
+directory for configuration.  The config file should look like this:
+
+    # Select whether random data is generated every request or only once when the
+    # app is initialized.  If you specify "dynamic" here, then new random data
+    # will be generated every request.  If you specify "static", then random data
+    # will be generated once and every request will see the same data.
+    mode = "dynamic"
+    
+    # Directory holding Heist templates
+    tdir = "snaplets/heist/templates"
+    
+    # List of files with custom enumerations for random generation
+    enums = ["titles.txt"]
+    
+    # Directory where static resources are located
+    staticDir = "static"
+    
+    # Route for accessing static data
+    staticRoute = ""
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
diff --git a/charade.cabal b/charade.cabal
new file mode 100644
--- /dev/null
+++ b/charade.cabal
@@ -0,0 +1,78 @@
+name:           charade
+version:        0.1
+synopsis:       Rapid prototyping websites with Snap and Heist
+description:
+  Charade is a tool for rapid website prototyping using Heist and Snap.
+  Charade-generated sites can easily be dropped into Snap applications
+  and work out of the box with no modification.
+  .
+  The main thing provided by this package is the charade executable that
+  serves your prototype sites.  The library provided contains a Heist splice
+  that you use to make all evidence of charade disappear in your production
+  app.
+  .
+  For more information, see the @README@: <https://github.com/soostone/charade/blob/master/README.md>
+
+license:        BSD3
+license-file:   LICENSE
+author:         Doug Beardsley
+maintainer:     doug.beardsley@soostone.com
+build-type:     Simple
+cabal-version:  >= 1.8
+homepage:       https://github.com/soostone/charade
+category:       Web
+
+extra-source-files:
+  CONTRIBUTORS,
+  LICENSE,
+  README.md
+
+Library
+  hs-source-dirs: src
+
+  exposed-modules:
+    Heist.Charade
+
+  build-depends:
+    base                >= 4       && < 5,
+    heist               >= 0.12    && < 0.13,
+    xmlhtml             >= 0.2     && < 0.3
+
+  if impl(ghc >= 6.12.0)
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-orphans -fno-warn-unused-do-bind
+  else
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-orphans
+
+Executable charade
+  hs-source-dirs: src
+  main-is: Charade.hs
+
+  build-depends:
+    QuickCheck          >= 2.5     && < 2.6,
+    base                >= 4       && < 5,
+    configurator        >= 0.2     && < 0.3,
+    containers          >= 0.5     && < 0.6,
+    filepath            >= 1.3     && < 1.4,
+    lens                >= 3.8     && < 3.10,
+    heist               >= 0.12    && < 0.13,
+    random              >= 1.0     && < 1.1,
+    snap                >= 0.12    && < 0.13,
+    snap-core           >= 0.9     && < 0.11,
+    snap-server         >= 0.9     && < 0.11,
+    text                >= 0.11    && < 0.12,
+    xmlhtml             >= 0.2     && < 0.3
+
+  ghc-prof-options: -prof -auto-all
+
+  if impl(ghc >= 6.12.0)
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-orphans -fno-warn-unused-do-bind
+  else
+    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2
+                 -fno-warn-orphans
+
+source-repository head
+  type:     git
+  location: https://github.com/Soostone/charade.git
diff --git a/src/Charade.hs b/src/Charade.hs
new file mode 100644
--- /dev/null
+++ b/src/Charade.hs
@@ -0,0 +1,236 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell   #-}
+module Main where
+
+-------------------------------------------------------------------------------
+import           Control.Lens hiding (elements)
+import qualified Data.Configurator as C
+import           Data.Configurator.Types
+import qualified Data.Map            as M
+import           Data.Maybe
+import           Data.Monoid
+import           Data.Text           (Text)
+import qualified Data.Text           as T
+import qualified Data.Text.IO        as T
+import           Data.Text.Read
+import           Heist
+import           Heist.Interpreted
+import           Snap
+import           Snap.Util.FileServe
+import           Snap.Snaplet.Heist
+import           System.FilePath
+import           System.Random
+import           Test.QuickCheck.Gen
+import           Text.XmlHtml
+------------------------------------------------------------------------------
+
+
+data App = App
+    { _heist :: Snaplet (Heist App)
+    }
+
+makeLenses ''App
+
+instance HasHeist App where
+    heistLens = subSnaplet heist
+
+------------------------------------------------------------------------------
+-- | Not sure whether we want these types specifically reified into an
+-- enumeration like this or to make them dynamic strings.  At any rate, I'm
+-- putting it like this now to record my thoughts on some of the types needed.
+data GenTypes
+  = IntT
+  -- ^ Integers
+  | RealT
+  -- ^ Reals
+  | EnumTextT
+  -- ^ Text that comes from an enumeration.  This is useful for generating
+  -- things like first names, last names, and other lists.
+  | ChildListT
+  -- ^ This type would be used on a heist tag that functions as a
+  -- runChildren-style list.
+  deriving (Read, Show, Eq, Enum)
+
+
+------------------------------------------------------------------------------
+-- | Integer generation
+genInt :: [Text] -> Gen [Node]
+genInt [] = genInt' 0 100
+genInt [a,b] = genInt' (read $ T.unpack a) (read $ T.unpack b)
+genInt _ = error "charade: invalid number of parameters to int generator"
+
+genInt' :: Int -> Int -> Gen [Node]
+genInt' a b = fmap ((:[]) . TextNode . T.pack . show) $ choose (a,b)
+
+
+------------------------------------------------------------------------------
+-- | Real generation
+genReal :: [Text] -> Gen [Node]
+genReal [] = genReal' 0 1
+genReal [a,b] = genReal' (read $ T.unpack a) (read $ T.unpack b)
+genReal _ = error "charade: invalid number of parameters to real generator"
+
+genReal' :: Double -> Double -> Gen [Node]
+genReal' a b = fmap ((:[]) . TextNode . T.pack . show) $ choose (a,b)
+
+
+------------------------------------------------------------------------------
+-- | List generation
+genList :: M.Map Text [Text] -> Node -> [Text] -> Gen [Node]
+genList enums node [] = genList' enums node 5
+genList enums node [n] = genList' enums node $ either error fst (decimal n)
+genList enums node [a,b] = do
+    let minCount = either error fst (decimal a) :: Int
+        maxCount = either error fst (decimal b) :: Int
+    count <- choose (minCount, maxCount)
+    genList' enums node count
+genList _ _ _ = error "charade: invalid number of parameters to list generator"
+
+genList' :: M.Map Text [Text] -> Node -> Int -> Gen [Node]
+genList' enums node count =
+    liftM concat $ vectorOf count $ liftM concat
+                 $ mapM (fakeNode enums) (childNodes node)
+
+
+------------------------------------------------------------------------------
+-- | List generation
+lorem :: Text
+lorem = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
+
+genLorem :: [Text] -> Gen [Node]
+genLorem [] = return [TextNode lorem]
+genLorem [n] = return [TextNode $ T.intercalate " " $ replicate count lorem]
+  where
+    count = either error fst (decimal n)
+genLorem _ = error "charade: invalid number of parameters to lorem generator"
+
+
+------------------------------------------------------------------------------
+-- | Enum generation
+genEnum :: [Text] -> [Node] -> Gen [Node]
+genEnum [] = fmap (:[]) . elements
+genEnum _ = error "charade: invalid number of parameters to enum generator"
+
+
+------------------------------------------------------------------------------
+-- | Enum generation
+genDynEnum :: M.Map Text [Text] -> [Text] -> Gen [Node]
+genDynEnum enums [file] = genEnum [] (map TextNode $ enums M.! file)
+genDynEnum _ _ = error "charade: must supply an file to the enum type"
+
+
+------------------------------------------------------------------------------
+-- | Uses the \"fake\" attribute to determine what type of random data should
+-- be generated for this node.  Usage might look something like this:
+--
+-- > <ul>
+-- >  <personListing fake="list 5">
+-- >   <li>
+-- >    <firstName fake="enum firstName"/> <lastName fake="enum lastName"/>
+-- >   </li>
+-- >  </personListing>
+-- > </ul>
+fakeNode :: M.Map Text [Text] -> Node -> Gen [Node]
+fakeNode enums n@(Element t a c) = case getAttribute "fake" n of
+    Nothing -> do
+      c' <- liftM concat $ mapM (fakeNode enums) c
+      return [Element t a c']
+    Just ty -> dispatchGenerator enums n (T.splitOn " " ty)
+fakeNode _ n = return [n]
+
+
+-- | Use the first token as the generator type and the rest of the list as
+-- parameters.
+dispatchGenerator :: M.Map Text [Text] -> Node -> [Text] -> Gen [Node]
+dispatchGenerator _ _ [] = return []
+dispatchGenerator enums node (_type:params) =
+    case T.unpack _type of
+      "bool"       -> genEnum params $ map TextNode ["true", "false"]
+      "yesno"      -> genEnum params $ map TextNode ["yes", "no"]
+      "int"        -> genInt params
+      "decimal"    -> genReal params
+      "list"       -> genList enums node params
+      "lorem"      -> genLorem params
+      "first-name" -> genEnum params $ map TextNode firstNames
+      "last-name"  -> genEnum params $ map TextNode lastNames
+      "enum"       -> genDynEnum enums params
+      x            -> error $ "charade: Generator type " ++ x ++
+                              " not recognized"
+
+
+charadeSplice :: MonadIO n => M.Map Text [Text] -> HeistT n n [Node]
+charadeSplice enums = do
+    stdGen <- liftIO newStdGen
+    (Element n attrs ch1) <- getParamNode
+    let ch2 = unGen (mapM (fakeNode enums) ch1) stdGen 1
+    ch3 <- runNodeList (concat ch2)
+    stopRecursion
+    return [Element n attrs ch3]
+
+
+------------------------------------------------------------------------------
+-- The web app
+------------------------------------------------------------------------------
+
+splices :: MonadIO n => M.Map Text [Text] -> [(Text, HeistT n n [Node])]
+splices enums = [("body", charadeSplice enums)]
+
+loadEnums :: Value -> IO [(Text, [Text])]
+loadEnums (List files) = mapM (loadEnum . convert) files
+loadEnums _ = error "charade.cfg: enums must be a list of files"
+
+loadEnum :: Maybe FilePath -> IO (Text, [Text])
+loadEnum Nothing = error "charade.cfg: all enums must be string filenames"
+loadEnum (Just p) = do
+    contents <- T.readFile p
+    return (T.pack p, T.lines contents)
+
+charadeInit :: SnapletInit App App
+charadeInit = makeSnaplet "charade" "A heist charade" Nothing $ do
+    rootDir <- getSnapletFilePath
+    cfg <- getSnapletUserConfig
+    tdir <- liftM (fromMaybe (error "Must specify tdir in charade.cfg")) $
+              liftIO $ C.lookup cfg "tdir"
+    mode <- liftIO $ (C.lookup cfg "mode" :: IO (Maybe Text))
+    enumFiles <- liftIO $ C.lookupDefault (List []) cfg "enums"
+    enumMap <- liftIO $ liftM M.fromList $ loadEnums enumFiles
+    staticRoute <- liftIO $ C.lookupDefault
+      (error "charade: Must specify staticRoute in charade.cfg")
+      cfg "staticRoute"
+    staticDir <- liftIO $ C.lookupDefault
+      (error "charade: Must specify staticDir in charade.cfg")
+      cfg "staticDir"
+
+    -- I didn't use the "templates" directory like we usually use.  This
+    -- probably needs to be a configurable parameter.
+    h <- nestSnaplet "heist" heist $
+           heistInit' "" $ mempty { hcLoadTimeSplices = defaultLoadTimeSplices }
+    addRoutes [ ("",          heistServe)
+              , ("heist/heistReload", with heist $ failIfNotLocal heistReloader)
+              , (staticRoute, serveDirectory staticDir)
+              ]
+
+    let heistConfig = case mode of
+          (Just "static") -> mempty { hcLoadTimeSplices = splices enumMap}
+          (Just "dynamic") -> mempty { hcInterpretedSplices = splices enumMap}
+          _ -> error "Must specify mode = 'static' or 'dynamic' in charade.cfg"
+
+    -- Heist doesn't have a catch-all splice, and attribute splices won't work
+    -- since we want to modify the actual node, so we use a load time
+    -- interpreted splice attached to the body tag.
+    addConfig h heistConfig
+    addTemplatesAt h "" (rootDir </> tdir)
+    return $ App h
+
+main :: IO ()
+main = do
+  (_,s,_) <- runSnaplet (Just "charade") charadeInit
+  quickHttpServe s
+
+firstNames :: [Text]
+firstNames =
+  ["James", "John", "Robert", "Michael", "William", "David", "Richard", "Charles", "Joseph", "Thomas", "Christopher", "Daniel", "Paul", "Mark", "Donald", "George", "Kenneth", "Steven", "Edward", "Brian", "Ronald", "Anthony", "Kevin", "Jason", "Matthew", "Gary", "Timothy", "Jose", "Larry", "Jeffrey", "Frank", "Scott", "Eric", "Stephen", "Andrew", "Raymond", "Gregory", "Joshua", "Jerry", "Dennis", "Walter", "Patrick", "Peter", "Harold", "Douglas", "Henry", "Carl", "Arthur", "Ryan", "Roger", "Joe", "Juan", "Jack", "Albert", "Jonathan", "Justin", "Terry", "Gerald", "Keith", "Samuel", "Willie", "Ralph", "Lawrence", "Nicholas", "Roy", "Benjamin", "Bruce", "Brandon", "Adam", "Harry", "Fred", "Wayne", "Billy", "Steve", "Louis", "Jeremy", "Aaron", "Randy", "Howard", "Eugene", "Carlos", "Russell", "Bobby", "Victor", "Martin", "Ernest", "Phillip", "Todd", "Jesse", "Craig", "Alan", "Shawn", "Clarence", "Sean", "Philip", "Chris", "Johnny", "Earl", "Jimmy", "Antonio", "Danny", "Bryan", "Tony", "Luis", "Mike", "Stanley", "Leonard", "Nathan", "Dale", "Manuel", "Rodney", "Curtis", "Norman", "Allen", "Marvin", "Vincent", "Glenn", "Jeffery", "Travis", "Jeff", "Chad", "Jacob", "Lee", "Melvin", "Alfred", "Kyle", "Francis", "Bradley", "Jesus", "Herbert", "Frederick", "Ray", "Joel", "Edwin", "Don", "Eddie", "Ricky", "Troy", "Randall", "Barry", "Alexander", "Bernard", "Mario", "Leroy", "Francisco", "Marcus", "Micheal", "Theodore", "Clifford", "Miguel", "Oscar", "Jay", "Jim", "Tom", "Calvin", "Alex", "Jon", "Ronnie", "Bill", "Lloyd", "Tommy", "Leon", "Derek", "Warren", "Darrell", "Jerome", "Floyd", "Leo", "Alvin", "Tim", "Wesley", "Gordon", "Dean", "Greg", "Jorge", "Dustin", "Pedro", "Derrick", "Dan", "Lewis", "Zachary", "Corey", "Herman", "Maurice", "Vernon", "Roberto", "Clyde", "Glen", "Hector", "Shane", "Ricardo", "Sam", "Rick", "Lester", "Brent", "Ramon", "Charlie", "Tyler", "Gilbert", "Gene", "Marc", "Reginald", "Ruben", "Brett", "Angel", "Nathaniel", "Rafael", "Leslie", "Edgar", "Milton", "Raul", "Ben", "Chester", "Cecil", "Duane", "Franklin", "Andre", "Elmer", "Brad", "Gabriel", "Ron", "Mitchell", "Roland", "Arnold", "Harvey", "Jared", "Adrian", "Karl", "Cory", "Claude", "Erik", "Darryl", "Jamie", "Neil", "Jessie", "Christian", "Javier", "Fernando", "Clinton", "Ted", "Mathew", "Tyrone", "Darren", "Lonnie", "Lance", "Cody", "Julio", "Kelly", "Kurt", "Allan", "Nelson", "Guy", "Clayton", "Hugh", "Max", "Dwayne", "Dwight", "Armando", "Felix", "Jimmie", "Everett", "Jordan", "Ian", "Wallace", "Ken", "Bob", "Jaime", "Casey", "Alfredo", "Alberto", "Dave", "Ivan", "Johnnie", "Sidney", "Byron", "Julian", "Isaac", "Morris", "Clifton", "Willard", "Daryl", "Ross", "Virgil", "Andy", "Marshall", "Salvador", "Perry", "Kirk", "Sergio", "Marion", "Tracy", "Seth", "Kent", "Terrance", "Rene", "Eduardo", "Terrence", "Enrique", "Freddie", "Wade", "Mary", "Patricia", "Linda", "Barbara", "Elizabeth", "Jennifer", "Maria", "Susan", "Margaret", "Dorothy", "Lisa", "Nancy", "Karen", "Betty", "Helen", "Sandra", "Donna", "Carol", "Ruth", "Sharon", "Michelle", "Laura", "Sarah", "Kimberly", "Deborah", "Jessica", "Shirley", "Cynthia", "Angela", "Melissa", "Brenda", "Amy", "Anna", "Rebecca", "Virginia", "Kathleen", "Pamela", "Martha", "Debra", "Amanda", "Stephanie", "Carolyn", "Christine", "Marie", "Janet", "Catherine", "Frances", "Ann", "Joyce", "Diane", "Alice", "Julie", "Heather", "Teresa", "Doris", "Gloria", "Evelyn", "Jean", "Cheryl", "Mildred", "Katherine", "Joan", "Ashley", "Judith", "Rose", "Janice", "Kelly", "Nicole", "Judy", "Christina", "Kathy", "Theresa", "Beverly", "Denise", "Tammy", "Irene", "Jane", "Lori", "Rachel", "Marilyn", "Andrea", "Kathryn", "Louise", "Sara", "Anne", "Jacqueline", "Wanda", "Bonnie", "Julia", "Ruby", "Lois", "Tina", "Phyllis", "Norma", "Paula", "Diana", "Annie", "Lillian", "Emily", "Robin", "Peggy", "Crystal", "Gladys", "Rita", "Dawn", "Connie", "Florence", "Tracy", "Edna", "Tiffany", "Carmen", "Rosa", "Cindy", "Grace", "Wendy", "Victoria", "Edith", "Kim", "Sherry", "Sylvia", "Josephine", "Thelma", "Shannon", "Sheila", "Ethel", "Ellen", "Elaine", "Marjorie", "Carrie", "Charlotte", "Monica", "Esther", "Pauline", "Emma", "Juanita", "Anita", "Rhonda", "Hazel", "Amber", "Eva", "Debbie", "April", "Leslie", "Clara", "Lucille", "Jamie", "Joanne", "Eleanor", "Valerie", "Danielle", "Megan", "Alicia", "Suzanne", "Michele", "Gail", "Bertha", "Darlene", "Veronica", "Jill", "Erin", "Geraldine", "Lauren", "Cathy", "Joann", "Lorraine", "Lynn", "Sally", "Regina", "Erica", "Beatrice", "Dolores", "Bernice", "Audrey", "Yvonne", "Annette", "June", "Samantha", "Marion", "Dana", "Stacy", "Ana", "Renee", "Ida", "Vivian", "Roberta", "Holly", "Brittany", "Melanie", "Loretta", "Yolanda", "Jeanette", "Laurie", "Katie", "Kristen", "Vanessa", "Alma", "Sue", "Elsie", "Beth", "Jeanne", "Vicki", "Carla", "Tara", "Rosemary", "Eileen", "Terri", "Gertrude", "Lucy", "Tonya", "Ella", "Stacey", "Wilma", "Gina", "Kristin", "Jessie", "Natalie", "Agnes", "Vera", "Willie", "Charlene", "Bessie", "Delores", "Melinda", "Pearl", "Arlene", "Maureen", "Colleen", "Allison", "Tamara", "Joy", "Georgia", "Constance", "Lillie", "Claudia", "Jackie", "Marcia", "Tanya", "Nellie", "Minnie", "Marlene", "Heidi", "Glenda", "Lydia", "Viola", "Courtney", "Marian", "Stella", "Caroline", "Dora", "Jo", "Vickie", "Mattie"]
+
+lastNames :: [Text]
+lastNames =
+  ["Smith", "Johnson", "Williams", "Jones", "Brown", "Davis", "Miller", "Wilson", "Moore", "Taylor", "Anderson", "Thomas", "Jackson", "White", "Harris", "Martin", "Thompson", "Garcia", "Martinez", "Robinson", "Clark", "Rodriguez", "Lewis", "Lee", "Walker", "Hall", "Allen", "Young", "Hernandez", "King", "Wright", "Lopez", "Hill", "Scott", "Green", "Adams", "Baker", "Gonzalez", "Nelson", "Carter", "Mitchell", "Perez", "Roberts", "Turner", "Phillips", "Campbell", "Parker", "Evans", "Edwards", "Collins", "Stewart", "Sanchez", "Morris", "Rogers", "Reed", "Cook", "Morgan", "Bell", "Murphy", "Bailey", "Rivera", "Cooper", "Richardson", "Cox", "Howard", "Ward", "Torres", "Peterson", "Gray", "Ramirez", "James", "Watson", "Brooks", "Sanders", "Price", "Bennett", "Wood", "Barnes", "Ross", "Henderson", "Coleman", "Jenkins", "Perry", "Powell", "Long", "Patterson", "Hughes", "Flores", "Washington", "Butler", "Simmons", "Foster", "Gonzales", "Bryant", "Alexander", "Russell", "Griffin", "Diaz", "Hayes"]
diff --git a/src/Heist/Charade.hs b/src/Heist/Charade.hs
new file mode 100644
--- /dev/null
+++ b/src/Heist/Charade.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell   #-}
+module Heist.Charade
+  ( charadeProductionSplice
+  ) where
+
+import           Heist
+import           Heist.Interpreted
+import           Text.XmlHtml
+
+
+------------------------------------------------------------------------------
+-- | Charade needs to provide a splice that can be bound to eliminate all
+-- charade-specific attributes from the markup.
+charadeProductionSplice :: Monad n => Splice n
+charadeProductionSplice = return . (:[]) . removeFake =<< getParamNode
+
+
+removeFake :: Node -> Node
+removeFake (Element tag attrs ch) = Element tag attrs' $ map removeFake ch
+  where
+    attrs' = filter ((/="fake") . fst) attrs
+removeFake n = n
+
+
