for _, file := range s.Files {
                fmt.Fprintf(out, "%s\n", file)
+               fmt.Fprintf(out, " canonical => ")
                if s.Target == nil {
-                       fmt.Fprintf(out, " *implicit* => %s\n", "!no target specified!")
+                       fmt.Fprintf(out, "%s\n", "!no target specified!")
                        continue
                }
+
+               trns, err := s.Target.Translate(file)
+               if err != nil {
+                       return err
+               }
+
+               fmt.Fprintf(out, "%s\n", trns)
+
        }
        return
 }
 
        Info       SiteInfo
        Shortcodes map[string]ShortcodeFunc
        timer      *nitro.B
-       Target     target.Publisher
+       Target     target.Output
 }
 
 type SiteInfo struct {
 
 func (s *Site) Analyze() {
        s.Process()
-       s.checkDescriptions()
+       s.initTarget()
+       s.ShowPlan(os.Stdout)
 }
 
 func (s *Site) prepTemplates() {
 func (s *Site) checkDescriptions() {
        for _, p := range s.Pages {
                if len(p.Description) < 60 {
-                       fmt.Print(p.FileName + " ")
+                       fmt.Println(p.FileName + " ")
                }
        }
 }
 
                if a := s.Tmpl.Lookup("rss.xml"); a != nil {
                        // XML Feed
-                       n.Url = Urlize(section + ".xml")
+                       n.Url = helpers.Urlize(section + ".xml")
                        n.Permalink = template.HTML(string(n.Site.BaseUrl) + n.Url)
                        y := s.NewXMLBuffer()
                        s.Tmpl.ExecuteTemplate(y, "rss.xml", n)
        return bytes.NewBufferString(header)
 }
 
-func (s *Site) WritePublic(path string, content []byte) (err error) {
-
+func (s *Site) initTarget() {
        if s.Target == nil {
                s.Target = &target.Filesystem{
                        PublishDir: s.absPublishDir(),
                        UglyUrls:   s.Config.UglyUrls,
                }
        }
+}
+
+func (s *Site) WritePublic(path string, content []byte) (err error) {
+       s.initTarget()
 
        if s.Config.Verbose {
                fmt.Println(path)
 
 import (
        "bytes"
        "testing"
+       "github.com/spf13/hugo/target"
 )
 
 func checkShowPlanExpected(t *testing.T, expected, got string) {
                t.Errorf("ShowPlan unexpectedly returned an error: %s", err)
        }
 
-       expected := "foo/bar/file.md\n *implicit* => !no target specified!\n"
+       expected := "foo/bar/file.md\n canonical => !no target specified!\n"
        checkShowPlanExpected(t, expected, out.String())
 }
+
+func TestFileTarget(t *testing.T) {
+       s := &Site{Target: new(target.Filesystem)}
+       s.Files = append(s.Files, "foo/bar/file.md")
+       out := new(bytes.Buffer)
+       s.ShowPlan(out)
+
+       expected := "foo/bar/file.md\n canonical => foo/bar/file/index.html\n"
+       checkShowPlanExpected(t, expected, out.String())
+}
+
+func TestFileTargetUgly(t *testing.T) {
+       s := &Site{Target: &target.Filesystem{UglyUrls: true}}
+       s.Files = append(s.Files, "foo/bar/file.md")
+       out := new(bytes.Buffer)
+       s.ShowPlan(out)
+
+       expected := "foo/bar/file.md\n canonical => foo/bar/file.html\n"
+       checkShowPlanExpected(t, expected, out.String())
+}
+
+
 
        return
 }
 
+func (t *InMemoryTarget) Translate(label string) (dest string, err error) {
+       return label, nil
+}
+
 func TestPageCount(t *testing.T) {
        target := new(InMemoryTarget)
        s := &Site{Target: target}
 
        Translate(string) (string, error)
 }
 
+type Output interface {
+       Publisher
+       Translator
+}
+
 type Filesystem struct {
        UglyUrls         bool
        DefaultExtension string
        if src == "/" {
                return "index.html", nil
        }
-       if fs.UglyUrls {
-               return src, nil
-       }
 
        dir, file := path.Split(src)
        ext := fs.extension(path.Ext(file))
        name := filename(file)
 
+       if fs.UglyUrls {
+               return path.Join(dir, fmt.Sprintf("%s%s", name, ext)), nil
+       }
+
        return path.Join(dir, name, fmt.Sprintf("index%s", ext)), nil
 }
 
 func (fs *Filesystem) extension(ext string) string {
+       switch ext {
+       case ".md", ".rst": // TODO make this list configurable.  page.go has the list of markup types.
+               return ".html"
+       }
+
        if ext != "" {
                return ext
        }