func (c *CGI) extension(suffix string) []string {
	var filename []string
	d, err := util.AssetDir("www")
	if err != nil {
		log.Fatal(err)
	}
	for _, fname := range d {
		if util.HasExt(fname, suffix) {
			filename = append(filename, fname)
		}
	}
	if util.IsDir(cfg.Docroot) {
		err = util.EachFiles(cfg.Docroot, func(f os.FileInfo) error {
			i := f.Name()
			if util.HasExt(i, suffix) {
				if !util.HasString(filename, i) {
					filename = append(filename, i)
				}
			}
			return nil
		})
		if err != nil {
			log.Println(err)
		}
	}
	sort.Strings(filename)
	return filename
}
extentions reads files with suffix in root dir and return them.
if __merged file exists return it when useMerged=true.
package cgi
import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"regexp"
	"sort"
	"strings"
	"time"
	"github.com/russross/blackfriday"
	"github.com/shingetsu-gou/shingetsu-gou/cfg"
	"github.com/shingetsu-gou/shingetsu-gou/tag"
	"github.com/shingetsu-gou/shingetsu-gou/tag/suggest"
	"github.com/shingetsu-gou/shingetsu-gou/tag/user"
	"github.com/shingetsu-gou/shingetsu-gou/thread"
	"github.com/shingetsu-gou/shingetsu-gou/util"
)
type CacheInfo struct {
	Cache   *thread.Cache
	Tags    tag.Slice
	Sugtags []*tag.Tag
	Title   string
}
type ListItem struct {
	Caches  []*CacheInfo
	StrOpts string
	Remove  bool
}
func checkCache(ca *thread.Cache, target, filter, tag string) (string, bool) {
	x := util.FileDecode(ca.Datfile)
	if x == "" {
		return "", false
	}
	if filter != "" && !strings.Contains(strings.ToLower(x), filter) {
		return "", false
	}
	if tag != "" {
		switch {
		case user.Has(ca.Datfile, strings.ToLower(tag)):
		case target == "recent" && suggest.HasTagstr(ca.Datfile, strings.ToLower(tag)):
		default:
			return "", false
		}
	}
	return x, true
}
func NewListItem(caches []*thread.Cache, remove bool, target string, search bool, filter, tag string) *ListItem {
	li := &ListItem{Remove: remove}
	li.Caches = make([]*CacheInfo, 0, len(caches))
	if search {
		li.StrOpts = "?search_new_file=yes"
	}
	for _, ca := range caches {
		x, ok := checkCache(ca, target, filter, tag)
		if !ok {
			continue
		}
		ci := &CacheInfo{Cache: ca}
		li.Caches = append(li.Caches, ci)
		ci.Title = util.EscapeSpace(x)
		if target == "recent" {
			strTags := make([]string, user.Len(ca.Datfile))
			for i, v := range user.GetByThread(ca.Datfile) {
				strTags[i] = strings.ToLower(v.Tagstr)
			}
			for _, st := range suggest.Get(ca.Datfile, nil) {
				if !util.HasString(strTags, strings.ToLower(st.Tagstr)) {
					ci.Sugtags = append(ci.Sugtags, st)
				}
			}
		}
		ci.Tags = user.GetByThread(ca.Datfile)
	}
	return li
}
type Defaults struct {
	AdminCGI    string
	GatewayCGI  string
	ThreadCGI   string
	ServerCGI   string
	Message     Message
	IsAdmin     bool
	IsFriend    bool
	Version     string
	DescChanges string
	DescNew     string
	DescRecent  string
	DescIndex   string
	DescSearch  string
	DescStatus  string
	Path        string
	EmptyList   template.HTML
}
type CGI struct {
	M        Message
	JC       *jsCache
	Req      *http.Request
	WR       http.ResponseWriter
	IsThread bool
}
func NewCGI(w http.ResponseWriter, r *http.Request) (*CGI, error) {
	c := &CGI{
		JC:  newJsCache(cfg.Docroot),
		WR:  w,
		M:   SearchMessage(r.Header.Get("Accept-Language"), cfg.FileDir),
		Req: r,
	}
	err := r.ParseForm()
	if err != nil {
		log.Println(err)
		return nil, err
	}
	return c, nil
}
func (c *CGI) Defaults() *Defaults {
	href := `<a href="` + cfg.GatewayURL + `/recent" title="` + c.M["desc_recent"] + `">` + c.M["recent"] + `</a>`
	return &Defaults{
		cfg.AdminURL,
		cfg.GatewayURL,
		cfg.ThreadURL,
		cfg.ServerURL,
		c.M,
		c.IsAdmin(),
		c.IsFriend(),
		cfg.Version,
		c.M["desc_changes"],
		c.M["desc_new"],
		c.M["desc_recent"],
		c.M["desc_index"],
		c.M["desc_search"],
		c.M["desc_status"],
		c.Path(),
		template.HTML(fmt.Sprintf(c.M["empty_list"], href)),
	}
}
func (c *CGI) Host() string {
	host := cfg.ServerName
	if host == "" {
		host = c.Req.Host
	}
	return host
}
func (c *CGI) IsAdmin() bool {
	m, err := regexp.MatchString(cfg.ReAdminStr, c.Req.RemoteAddr)
	if err != nil {
		log.Fatal(err)
	}
	return m
}
func (c *CGI) IsFriend() bool {
	m, err := regexp.MatchString(cfg.ReFriendStr, c.Req.RemoteAddr)
	if err != nil {
		log.Fatal(err)
	}
	return m
}
func (c *CGI) isVisitor() bool {
	m, err := regexp.MatchString(cfg.ReVisitorStr, c.Req.RemoteAddr)
	if err != nil {
		log.Fatal(err)
	}
	return m
}
func (c *CGI) Path() string {
	p := strings.Split(c.Req.URL.Path, "/")
	var path string
	if len(p) > 1 {
		path = strings.Join(p[2:], "/")
	}
	return path
}