Index: trunk/testdata/sugar/.test/index.html
===================================================================
--- trunk/testdata/sugar/.test/index.html	(revision 18)
+++ trunk/testdata/sugar/.test/index.html	(revision 18)
@@ -0,0 +1,5 @@
+<html>
+	<body>
+		<p>Hello world</p>
+	</body>
+</html>
Index: trunk/testdata/sugar/.test/styles.css
===================================================================
--- trunk/testdata/sugar/.test/styles.css	(revision 18)
+++ trunk/testdata/sugar/.test/styles.css	(revision 18)
@@ -0,0 +1,1 @@
+body{font:100% Helvetica, sans-serif;color:blue;}
Index: trunk/testdata/sugar/index.amber
===================================================================
--- trunk/testdata/sugar/index.amber	(revision 18)
+++ trunk/testdata/sugar/index.amber	(revision 18)
@@ -0,0 +1,3 @@
+html
+	body
+		p Hello world
Index: trunk/testdata/sugar/styles.gcss
===================================================================
--- trunk/testdata/sugar/styles.gcss	(revision 18)
+++ trunk/testdata/sugar/styles.gcss	(revision 18)
@@ -0,0 +1,6 @@
+$base-font: Helvetica, sans-serif
+$main-color: blue
+
+body
+  font: 100% $base-font
+  color: $main-color
Index: trunk/zs.go
===================================================================
--- trunk/zs.go	(revision 17)
+++ trunk/zs.go	(revision 18)
@@ -14,5 +14,7 @@
 	"time"
 
+	"github.com/eknkc/amber"
 	"github.com/russross/blackfriday"
+	"github.com/yosssi/gcss"
 )
 
@@ -22,6 +24,10 @@
 )
 
-type EvalFn func(args []string, vars map[string]string) (string, error)
-
+type Vars map[string]string
+
+type EvalFn func(args []string, vars Vars) (string, error)
+
+// Splits a string in exactly two parts by delimiter
+// If no delimiter is found - the second string is be empty
 func split2(s, delim string) (string, string) {
 	parts := strings.SplitN(s, delim, 2)
@@ -33,7 +39,13 @@
 }
 
-func md(path, s string) (map[string]string, string) {
+// Parses markdown content. Returns parsed header variables and content
+func md(path string) (Vars, string, error) {
+	b, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, "", err
+	}
+	s := string(b)
 	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
-	v := map[string]string{
+	v := Vars{
 		"file":   path,
 		"url":    url,
@@ -42,5 +54,5 @@
 	}
 	if strings.Index(s, "\n\n") == -1 {
-		return map[string]string{}, s
+		return Vars{}, s, nil
 	}
 	header, body := split2(s, "\n\n")
@@ -52,8 +64,8 @@
 		v["url"] = v["url"][2:]
 	}
-	return v, body
-}
-
-func render(s string, vars map[string]string, eval EvalFn) (string, error) {
+	return v, body, nil
+}
+
+func render(s string, vars Vars, eval EvalFn) (string, error) {
 	delim_open := "{{"
 	delim_close := "}}"
@@ -88,5 +100,6 @@
 }
 
-func env(vars map[string]string) []string {
+// Converts zs markdown variables into environment variables
+func env(vars Vars) []string {
 	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
 	env = append(env, os.Environ()...)
@@ -99,5 +112,7 @@
 }
 
-func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
+// Runs command with given arguments and variables, intercepts stderr and
+// redirects stdout into the given writer
+func run(cmd string, args []string, vars Vars, output io.Writer) error {
 	var errbuf bytes.Buffer
 	c := exec.Command(cmd, args...)
@@ -118,5 +133,5 @@
 }
 
-func eval(cmd []string, vars map[string]string) (string, error) {
+func eval(cmd []string, vars Vars) (string, error) {
 	outbuf := bytes.NewBuffer(nil)
 	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
@@ -136,9 +151,8 @@
 
 func buildMarkdown(path string) error {
-	b, err := ioutil.ReadFile(path)
-	if err != nil {
-		return err
-	}
-	v, body := md(path, string(b))
+	v, body, err := md(path)
+	if err != nil {
+		return err
+	}
 	content, err := render(body, v, eval)
 	if err != nil {
@@ -149,5 +163,5 @@
 }
 
-func buildPlain(path string, vars map[string]string) error {
+func buildPlain(path string, vars Vars) error {
 	b, err := ioutil.ReadFile(path)
 	if err != nil {
@@ -167,4 +181,43 @@
 	}
 	return nil
+}
+
+func buildGCSS(path string) error {
+	f, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	s := strings.TrimSuffix(path, ".gcss") + ".css"
+	log.Println(s)
+	css, err := os.Create(filepath.Join(PUBDIR, s))
+	if err != nil {
+		return err
+	}
+
+	defer f.Close()
+	defer css.Close()
+
+	_, err = gcss.Compile(css, f)
+	return err
+}
+
+func buildAmber(path string, vars Vars) error {
+	a := amber.New()
+	err := a.ParseFile(path)
+	if err != nil {
+		return err
+	}
+	t, err := a.Compile()
+	if err != nil {
+		return err
+	}
+	//amber.FuncMap = amber.FuncMap
+	s := strings.TrimSuffix(path, ".amber") + ".html"
+	f, err := os.Create(filepath.Join(PUBDIR, s))
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return t.Execute(f, vars)
 }
 
@@ -203,8 +256,15 @@
 				ext := filepath.Ext(path)
 				if ext == ".md" || ext == ".mkd" {
-					log.Println("mkd: ", path)
+					log.Println("md: ", path)
 					return buildMarkdown(path)
 				} else if ext == ".html" || ext == ".xml" {
-					return buildPlain(path, map[string]string{})
+					log.Println("html: ", path)
+					return buildPlain(path, Vars{})
+				} else if ext == ".amber" {
+					log.Println("html: ", path)
+					return buildAmber(path, Vars{})
+				} else if ext == ".gcss" {
+					log.Println("css: ", path)
+					return buildGCSS(path)
 				} else {
 					log.Println("raw: ", path)
@@ -247,6 +307,5 @@
 			return
 		}
-		if b, err := ioutil.ReadFile(args[0]); err == nil {
-			vars, _ := md(args[0], string(b))
+		if vars, _, err := md(args[0]); err == nil {
 			if len(args) > 1 {
 				for _, a := range args[1:] {
@@ -262,5 +321,5 @@
 		}
 	default:
-		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
+		err := run(path.Join(ZSDIR, cmd), args, Vars{}, os.Stdout)
 		if err != nil {
 			log.Println(err)
Index: trunk/zs_test.go
===================================================================
--- trunk/zs_test.go	(revision 17)
+++ trunk/zs_test.go	(revision 18)
@@ -4,4 +4,5 @@
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"os"
@@ -32,6 +33,12 @@
 }
 
+func tmpfile(path, s string) string {
+	ioutil.WriteFile(path, []byte(s), 0644)
+	return path
+}
+
 func TestMD(t *testing.T) {
-	v, body := md("foo.md", `
+	defer os.Remove("foo.md")
+	v, body, _ := md(tmpfile("foo.md", `
 	title: Hello, world!
 	keywords: foo, bar, baz
@@ -39,5 +46,5 @@
 	bayan: [:|||:]
 
-this: is a content`)
+this: is a content`))
 	if v["title"] != "Hello, world!" {
 		t.Error()
@@ -57,5 +64,5 @@
 
 	// Test empty md
-	v, body = md("foo.md", "")
+	v, body, _ = md(tmpfile("foo.md", ""))
 	if len(v) != 0 || len(body) != 0 {
 		t.Error(v, body)
@@ -63,5 +70,5 @@
 
 	// Test empty header
-	v, body = md("foo.md", "Hello")
+	v, body, _ = md(tmpfile("foo.md", "Hello"))
 	if len(v) != 0 || body != "Hello" {
 		t.Error(v, body)
@@ -70,5 +77,5 @@
 
 func TestRender(t *testing.T) {
-	eval := func(a []string, vars map[string]string) (string, error) {
+	eval := func(a []string, vars Vars) (string, error) {
 		return "hello", nil
 	}
