view/template.go
func InitWatcher(pattern string, f func(string) error, ef func(error)) (err error) {
	if err = f(pattern); err != nil {
		return
	}
	if watcher.Watcher == nil {
		watcher.Watcher, err = fsnotify.NewWatcher()
		if err != nil {
			return
		}
		watcher.closer = make(chan bool)
	}
	go func() {
		atomic.AddUint32(&watcher.count, 1)
		for {
			select {
			case <-watcher.Events:
				if err := f(pattern); err != nil {
					ef(err)
				}
			case err := <-watcher.Errors:
				if ef != nil {
					ef(err)
				}
			case <-watcher.closer:
				break
			}
		}
	}()

	var matches []string
	matches, err = filepath.Glob(pattern)
	if err != nil {
		return
	}
	for _, v := range matches {
		if err = watcher.Add(v); err != nil {
			return
		}
	}
	return
}
func InitWatcher(pattern string, f func(string) error, ef func(error)) (err error) {
	if err = f(pattern); err != nil {
		return
	}
	if watcher.Watcher == nil {
		watcher.Watcher, err = fsnotify.NewWatcher()
		if err != nil {
			return
		}
		watcher.closer = make(chan bool)
	}
	go func() {
		atomic.AddUint32(&watcher.count, 1)
		for {
			select {
			case <-watcher.Events:
				if err := f(pattern); err != nil {
					ef(err)
				}
			case err := <-watcher.Errors:
				if ef != nil {
					ef(err)
				}
			case <-watcher.closer:
				break
			}
		}
	}()

	var matches []string
	matches, err = filepath.Glob(pattern)
	if err != nil {
		return
	}
	for _, v := range matches {
		if err = watcher.Add(v); err != nil {
			return
		}
	}
	return
}
// InitWatcher initialzes a watcher to watch templates changes in the `pattern`.
// f would be InitHtmlTemplates or InitTextTemplates.
// If the watcher raises an error internally, the callback function ef will be executed.
// ef can be nil witch represents ignoring all internal errors.