diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) Adam Langley
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. 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.
+
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE 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 AUTHORS 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/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/Text/CTemplate.hs b/Text/CTemplate.hs
new file mode 100644
--- /dev/null
+++ b/Text/CTemplate.hs
@@ -0,0 +1,90 @@
+-- | CTemplate is the template system that Google uses for many of their sites,
+--   including the search results from the main www.google.com web search. It's
+--   simple templating system, but has easy to use escaping functions.
+--
+--   See <http://goog-ctemplate.sourceforge.net/doc/howto.html> for
+--   documentation (esp see the Tips link at the end of that)
+module Text.CTemplate
+  ( Dictionary(..)
+  , Variable(..)
+  , Option(..)
+  , expand
+  , setTemplateRootDirectory
+  ) where
+
+import Foreign
+import Foreign.C
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Unsafe as B
+
+-- | This is a dictionary. Relative filenames are resolved in the current
+--   directory
+data Dictionary = Dictionary FilePath [(String, Variable)] deriving (Show, Eq)
+
+data Variable = StringV String  -- ^ a string value (note - no char encoding performed)
+              | BSV B.ByteString  -- ^ a string value from a ByteString
+              | SectionV [[(String, Variable)]]  -- ^ a (possibly repeated) section
+              | IncludedV Dictionary  -- ^ an included dictionary
+              deriving (Show, Eq)
+
+data Option = DontStrip
+            | StripBlankLines
+            | StripWhitespace
+            deriving (Show, Eq, Enum)
+
+-- | This is the type of the C-side dictionary object
+data Dictionary_
+-- | Likewise, this is the type of the C-side template
+data Template_
+
+foreign import ccall unsafe "ct_load_template" _load_template :: CString -> CInt -> IO (Ptr Template_)
+foreign import ccall unsafe "ct_new_dict" _new_dict :: IO (Ptr Dictionary_)
+foreign import ccall unsafe "ct_set_string" _set_string :: Ptr Dictionary_ -> CString -> CString -> IO ()
+foreign import ccall unsafe "ct_set_bytes" _set_bytes :: Ptr Dictionary_ -> CString -> Ptr CChar -> CInt -> IO ()
+foreign import ccall unsafe "ct_new_section" _new_section :: Ptr Dictionary_ -> CString -> IO (Ptr Dictionary_)
+foreign import ccall unsafe "ct_new_included" _new_included :: Ptr Dictionary_ -> CString -> IO (Ptr Dictionary_)
+foreign import ccall unsafe "ct_set_filename" _set_filename :: Ptr Dictionary_ -> CString -> IO ()
+foreign import ccall unsafe "ct_expand" _expand :: Ptr Template_ -> Ptr Dictionary_ -> IO (Ptr CChar)
+
+translateVariable :: Ptr Dictionary_ -> (String, Variable) -> IO ()
+translateVariable dict (v, StringV s) =
+  withCString v $ \v ->
+    withCString s $ \s ->
+      _set_string dict v s
+
+translateVariable dict (v, BSV bs) =
+  withCString v $ \v ->
+    B.unsafeUseAsCStringLen bs $ \(ptr, len) ->
+      _set_bytes dict v ptr $ fromIntegral len
+
+translateVariable dict (v, SectionV varses) =
+  withCString v $ \v ->
+    flip mapM_ varses $ \vars ->
+      _new_section dict v >>= \dict -> mapM_ (translateVariable dict) vars
+
+translateVariable dict (v, IncludedV (Dictionary filename vars)) =
+  withCString v $ \v ->
+    _new_included dict v >>= \dict ->
+      withCString filename $ \ptr ->
+        _set_filename dict ptr >> mapM_ (translateVariable dict) vars
+
+-- | Expand a template given the values to fill it
+expand :: Option -> Dictionary -> IO (Maybe B.ByteString)
+expand option (Dictionary filename vars) = do
+  template <- withCString filename $ \ptr -> _load_template ptr $ fromIntegral $ fromEnum option
+  if template == nullPtr
+     then return Nothing
+     else do dict <- _new_dict
+             mapM_ (translateVariable dict) vars
+             str <- _expand template dict
+             bs <- B.packCString str
+             free str
+             return $ Just bs
+
+foreign import ccall unsafe "ct_set_root" _set_root :: Ptr CChar -> IO ()
+
+-- | Set the directory where templates with non-absolute filenames will be
+--   loaded from
+setTemplateRootDirectory :: FilePath -> IO ()
+setTemplateRootDirectory filename =
+  withCString filename $ \ptr -> _set_root ptr
diff --git a/cbits/ctemplate.cc b/cbits/ctemplate.cc
new file mode 100644
--- /dev/null
+++ b/cbits/ctemplate.cc
@@ -0,0 +1,50 @@
+#include <string>
+#include <stdio.h>
+#include <stdlib.h>
+#include <google/template.h>
+
+extern "C" {
+void *ct_load_template(const char *filename, int option) {
+  return google::Template::GetTemplate(filename, (google::Strip) option);
+}
+
+void *ct_new_dict() {
+  return new google::TemplateDictionary("");
+}
+
+void ct_set_string(google::TemplateDictionary *dict, const char *key,
+                   const char *value) {
+  dict->SetValue(key, value);
+}
+
+void ct_set_bytes(google::TemplateDictionary *dict, const char *key, const char *bytes,
+                  const int length) {
+  dict->SetValue(key, std::string(bytes, length));
+}
+
+void *ct_new_section(google::TemplateDictionary *dict, const char *key) {
+  return dict->AddSectionDictionary(key);
+}
+
+void *ct_new_included(google::TemplateDictionary *dict, const char *key) {
+  return dict->AddIncludeDictionary(key);
+}
+
+void ct_set_filename(google::TemplateDictionary *dict, const char *filename) {
+  dict->SetFilename(filename);
+}
+
+char *ct_expand(google::Template *tmpl, google::TemplateDictionary *dict) {
+  std::string result;
+  tmpl->Expand(&result, dict);
+  char *ret = (char *) malloc(result.size() + 1);
+  memcpy(ret, result.c_str(), result.size() + 1);
+
+  return ret;
+}
+
+void ct_set_root(const char *path) {
+  google::Template::SetTemplateRootDirectory(path);
+}
+
+}
diff --git a/ctemplate.cabal b/ctemplate.cabal
new file mode 100644
--- /dev/null
+++ b/ctemplate.cabal
@@ -0,0 +1,25 @@
+Name: ctemplate
+Synopsis: Binding to the Google ctemplate library
+Description:
+  CTemplate is the library that Google uses to render most of their sites
+  (including the www.google.com search). It's a simple templating system, but
+  includes many, easy to use, escaping functions.
+Version: 0.1
+License: BSD3
+License-File: LICENSE
+Author: Adam Langley <agl@imperialviolet.org>
+Stability: experimental
+Homepage: http://darcs.imperialviolet.org/ctemplate
+Category: Text
+Tested-With: GHC == 6.8.2
+Build-Depends: base, bytestring
+Exposed-Modules:  Text.CTemplate
+Extensions: ForeignFunctionInterface, EmptyDataDecls
+ghc-options: -Wall -fno-warn-name-shadowing
+build-type: Simple
+C-Sources: cbits/ctemplate.cc
+Extra-Source-Files:
+        examples/test.tmpl
+        examples/included.tmpl
+        examples/example.hs
+Extra-Libraries: ctemplate
diff --git a/examples/example.hs b/examples/example.hs
new file mode 100644
--- /dev/null
+++ b/examples/example.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import qualified Data.ByteString as B
+import Text.CTemplate
+
+main = do
+  Just bs <- expand DontStrip $ Dictionary "test.tmpl"
+    [("NAME", StringV "Adam"), ("S", SectionV [[("VALUE", StringV "0")], [("VALUE", StringV "1")]]),
+     ("INCLUDED", IncludedV $ Dictionary "included.tmpl" []),
+     ("HTML", StringV "<br>")]
+  B.putStr bs
diff --git a/examples/included.tmpl b/examples/included.tmpl
new file mode 100644
--- /dev/null
+++ b/examples/included.tmpl
@@ -0,0 +1,1 @@
+This is an included template
diff --git a/examples/test.tmpl b/examples/test.tmpl
new file mode 100644
--- /dev/null
+++ b/examples/test.tmpl
@@ -0,0 +1,9 @@
+Hello {{NAME}}, NAME is a simple variable,
+{{#S}}This is a repeatable section, with a value: {{VALUE}}
+{{/S}}
+
+If you don't give a value for a variable, it ends up "{{NONAME}}" (blank)
+
+{{>INCLUDED}}
+
+We can try an include HTML in the following, but it will be escaped: {{HTML:h}}
