func New(opts ...Option) (*Parser, error) {
	p := &Parser{
		BookmarksPath:      DefaultBookmarksPath,
		IgnoreBookmarklets: DefaultIgnoreBookmarklets,
		uid2Folder:         map[string]*Folder{},
		uid2Bookmark:       map[string]*Bookmark{},
		uid2Type:           map[string]string{},
	}
	p.Configure(opts...)
	if err := p.Parse(); err != nil {
		return nil, err
	}
	return p, nil
}
New creates a new Parser with the specified options and calls Parser.Parse().
package safari
import (
	"errors"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
	"howett.net/plist"
)
const (
	WebBookmarkTypeLeaf  = "WebBookmarkTypeLeaf"
	WebBookmarkTypeList  = "WebBookmarkTypeList"
	WebBookmarkTypeProxy = "WebBookmarkTypeProxy"
)
const (
	NameBookmarksBar  = "BookmarksBar"
	NameBookmarksMenu = "BookmarksMenu"
	NameReadingList   = "com.apple.ReadingList"
)
const (
	TypeFolder   = "folder"
	TypeBookmark = "bookmark"
)
var (
	DefaultBookmarksPath      = filepath.Join(os.Getenv("HOME"), "Library/Safari/Bookmarks.plist")
	DefaultIgnoreBookmarklets = false
	parser *Parser  
)
type Item interface {
	Title() string
	UID() string
}
type rawRL struct {
	DateAdded       time.Time
	DateLastFetched time.Time
	DateLastViewed  time.Time
	PreviewText     string
}
type rawBookmark struct {
	RawTitle    string            `plist:"Title"`
	Type        string            `plist:"WebBookmarkType"`
	URL         string            `plist:"URLString"`
	UUID        string            `plist:"WebBookmarkUUID"`
	ReadingList *rawRL            `plist:"ReadingList"`
	URIDict     map[string]string `plist:"URIDictionary"`
	Children    []*rawBookmark
}
func (rb *rawBookmark) Title() string {
	if rb.RawTitle != "" {
		return rb.RawTitle
	}
	return rb.URIDict["title"]
}
type Folder struct {
	title           string
	Ancestors       []*Folder    
	Bookmarks       []*Bookmark  
	Folders         []*Folder    
	uid             string
	isReadingList   bool
	isBookmarksBar  bool
	isBookmarksMenu bool
}
func (f *Folder) Title() string { return f.title }
func (f *Folder) UID() string { return f.uid }
func (f *Folder) IsReadingList() bool { return f.isReadingList }
func (f *Folder) IsBookmarksBar() bool { return f.isBookmarksBar }
func (f *Folder) IsBookmarksMenu() bool { return f.isBookmarksMenu }
type Bookmark struct {
	title     string
	URL       string
	Ancestors []*Folder  
	Preview   string
	uid       string
}
func (bm *Bookmark) Title() string { return bm.title }
func (bm *Bookmark) UID() string { return bm.uid }
func (bm *Bookmark) Folder() *Folder {
	if len(bm.Ancestors) == 0 {
		return nil
	}
	return bm.Ancestors[len(bm.Ancestors)-1]
}
func (bm *Bookmark) InReadingList() bool {
	f := bm.Folder()
	if f == nil {
		return false
	}
	return f.IsReadingList()
}
func (bm *Bookmark) IsBookmarklet() bool {
	return strings.HasPrefix(bm.URL, "javascript:")
}
func (bm *Bookmark) Hostname() (string, error) {
	u, err := url.Parse(bm.URL)
	if err != nil {
		return "", err
	}
	return u.Hostname(), nil
}
func (bm *Bookmark) ToJS() (string, error) {
	if !bm.IsBookmarklet() {
		return "", errors.New("not a bookmarklet")
	}
	return url.PathUnescape(bm.URL[11:])
}
type Option func(*Parser)
func BookmarksPath(path string) Option {
	return func(p *Parser) { p.BookmarksPath = path }
}
func IgnoreBookmarklets(v bool) Option {
	return func(p *Parser) { p.IgnoreBookmarklets = v }
}
type Parser struct {
	BookmarksPath      string
	IgnoreBookmarklets bool          
	Bookmarks          []*Bookmark   
	BookmarksRL        []*Bookmark   
	Folders            []*Folder     
	BookmarksBar       *Folder       
	BookmarksMenu      *Folder       
	ReadingList        *Folder       
	raw                *rawBookmark  
	uid2Folder         map[string]*Folder
	uid2Bookmark       map[string]*Bookmark
	uid2Type           map[string]string
}