From 3f36200862e3dbcdefdb3e49877c81938609007d Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 6 Mar 2016 19:18:46 +0000 Subject: [PATCH] update file structure [ci skip] --- config/config.go | 2 +- hugo.go | 13 +- {browse => routes/browse}/browse.go | 0 {browse => routes/browse}/delete.go | 2 +- {browse => routes/browse}/get.go | 8 +- {browse => routes/browse}/post.go | 5 +- {browse => routes/browse}/put.go | 2 +- {editor => routes/editor}/editor.go | 0 {editor => routes/editor}/get.go | 12 +- {editor => routes/editor}/post.go | 4 +- {git => routes/git}/git.go | 0 {git => routes/git}/post.go | 2 +- tools/commands/commands.go | 15 +++ tools/files/files.go | 30 +++++ tools/files/files_test.go | 11 ++ .../files}/test_data/file_to_copy.txt | 0 .../frontmatter}/frontmatter.go | 6 +- {hugo => tools/hugo}/hugo.go | 34 ++++- .../utils.go => tools/templates/templates.go | 122 +----------------- .../templates/templates_test.go | 10 +- tools/types/types.go | 13 ++ tools/utils/utils.go | 45 +++++++ utils/test_data/copied_file.txt | 9 -- 23 files changed, 180 insertions(+), 165 deletions(-) rename {browse => routes/browse}/browse.go (100%) rename {browse => routes/browse}/delete.go (95%) rename {browse => routes/browse}/get.go (82%) rename {browse => routes/browse}/post.go (95%) rename {browse => routes/browse}/put.go (96%) rename {editor => routes/editor}/editor.go (100%) rename {editor => routes/editor}/get.go (93%) rename {editor => routes/editor}/post.go (98%) rename {git => routes/git}/git.go (100%) rename {git => routes/git}/post.go (97%) create mode 100644 tools/commands/commands.go create mode 100644 tools/files/files.go create mode 100644 tools/files/files_test.go rename {utils => tools/files}/test_data/file_to_copy.txt (100%) rename {frontmatter => tools/frontmatter}/frontmatter.go (97%) rename {hugo => tools/hugo}/hugo.go (90%) rename utils/utils.go => tools/templates/templates.go (52%) rename utils/utils_test.go => tools/templates/templates_test.go (91%) create mode 100644 tools/types/types.go create mode 100644 tools/utils/utils.go delete mode 100644 utils/test_data/copied_file.txt diff --git a/config/config.go b/config/config.go index 38f2d9e3..eb8a3802 100644 --- a/config/config.go +++ b/config/config.go @@ -5,7 +5,7 @@ import ( "path/filepath" "strings" - "github.com/hacdias/caddy-hugo/hugo" + "github.com/hacdias/caddy-hugo/tools/hugo" "github.com/mholt/caddy/caddy/setup" ) diff --git a/hugo.go b/hugo.go index ede1be6e..4f3b0972 100644 --- a/hugo.go +++ b/hugo.go @@ -15,11 +15,12 @@ import ( "strings" "github.com/hacdias/caddy-hugo/assets" - "github.com/hacdias/caddy-hugo/browse" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/editor" - "github.com/hacdias/caddy-hugo/git" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/routes/browse" + "github.com/hacdias/caddy-hugo/routes/editor" + "github.com/hacdias/caddy-hugo/routes/git" + "github.com/hacdias/caddy-hugo/tools/commands" + "github.com/hacdias/caddy-hugo/tools/hugo" "github.com/mholt/caddy/caddy/setup" "github.com/mholt/caddy/middleware" ) @@ -46,14 +47,14 @@ func Setup(c *setup.Controller) (middleware.Middleware, error) { } if create { - err := utils.RunCommand(config.Hugo, []string{"new", "site", config.Path, "--force"}, ".") + err := commands.Run(config.Hugo, []string{"new", "site", config.Path, "--force"}, ".") if err != nil { log.Panic(err) } } // Generates the Hugo website for the first time the plugin is activated. - go utils.Run(config, true) + go hugo.Run(config, true) return func(next middleware.Handler) middleware.Handler { return &CaddyHugo{Next: next, Config: config} diff --git a/browse/browse.go b/routes/browse/browse.go similarity index 100% rename from browse/browse.go rename to routes/browse/browse.go diff --git a/browse/delete.go b/routes/browse/delete.go similarity index 95% rename from browse/delete.go rename to routes/browse/delete.go index abc0d3f8..e88d3cfe 100644 --- a/browse/delete.go +++ b/routes/browse/delete.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/utils" ) // DELETE handles the delete requests on browse pages diff --git a/browse/get.go b/routes/browse/get.go similarity index 82% rename from browse/get.go rename to routes/browse/get.go index 453b2388..1385b3ec 100644 --- a/browse/get.go +++ b/routes/browse/get.go @@ -5,7 +5,7 @@ import ( "text/template" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/templates" "github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware/browse" ) @@ -14,11 +14,11 @@ import ( // the Browse Caddy middleware. func GET(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { functions := template.FuncMap{ - "CanBeEdited": utils.CanBeEdited, - "Defined": utils.Defined, + "CanBeEdited": templates.CanBeEdited, + "Defined": templates.Defined, } - tpl, err := utils.GetTemplate(r, functions, "browse") + tpl, err := templates.Get(r, functions, "browse") if err != nil { return http.StatusInternalServerError, err diff --git a/browse/post.go b/routes/browse/post.go similarity index 95% rename from browse/post.go rename to routes/browse/post.go index 990937fb..6240e40f 100644 --- a/browse/post.go +++ b/routes/browse/post.go @@ -11,7 +11,8 @@ import ( "strings" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/commands" + "github.com/hacdias/caddy-hugo/tools/utils" ) // POST handles the POST method on browse page. It's used to create new files, @@ -65,7 +66,7 @@ func POST(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) args = append(args, "--kind", archetype) } - if err := utils.RunCommand(c.Hugo, args, c.Path); err != nil { + if err := commands.Run(c.Hugo, args, c.Path); err != nil { return utils.RespondJSON(w, map[string]string{ "message": "Something went wrong.", }, 500, err) diff --git a/browse/put.go b/routes/browse/put.go similarity index 96% rename from browse/put.go rename to routes/browse/put.go index 45baf502..6a3311a3 100644 --- a/browse/put.go +++ b/routes/browse/put.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/utils" ) // PUT handles the HTTP PUT request for all /admin/browse related requests. diff --git a/editor/editor.go b/routes/editor/editor.go similarity index 100% rename from editor/editor.go rename to routes/editor/editor.go diff --git a/editor/get.go b/routes/editor/get.go similarity index 93% rename from editor/get.go rename to routes/editor/get.go index 170d6447..33df6751 100644 --- a/editor/get.go +++ b/routes/editor/get.go @@ -11,8 +11,8 @@ import ( "text/template" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/frontmatter" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/frontmatter" + "github.com/hacdias/caddy-hugo/tools/templates" "github.com/spf13/hugo/parser" ) @@ -30,7 +30,7 @@ type editor struct { func GET(w http.ResponseWriter, r *http.Request, c *config.Config, filename string) (int, error) { // Check if the file format is supported. If not, send a "Not Acceptable" // header and an error - if !utils.CanBeEdited(filename) { + if !templates.CanBeEdited(filename) { return http.StatusNotAcceptable, errors.New("File format not supported.") } @@ -110,11 +110,11 @@ func GET(w http.ResponseWriter, r *http.Request, c *config.Config, filename stri // Create the functions map, then the template, check for erros and // execute the template if there aren't errors functions := template.FuncMap{ - "SplitCapitalize": utils.SplitCapitalize, - "Defined": utils.Defined, + "SplitCapitalize": templates.SplitCapitalize, + "Defined": templates.Defined, } - tpl, err := utils.GetTemplate(r, functions, "editor", "frontmatter") + tpl, err := templates.Get(r, functions, "editor", "frontmatter") if err != nil { return http.StatusInternalServerError, err diff --git a/editor/post.go b/routes/editor/post.go similarity index 98% rename from editor/post.go rename to routes/editor/post.go index 0f6f1207..7102a32a 100644 --- a/editor/post.go +++ b/routes/editor/post.go @@ -11,7 +11,7 @@ import ( "time" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/commands" "github.com/robfig/cron" "github.com/spf13/cast" "github.com/spf13/hugo/parser" @@ -144,7 +144,7 @@ func parseCompleteFile(r *http.Request, c *config.Config, rawFile map[string]int return } - go utils.Run(c, false) + go commands.Run(c, false) }) scheduler.Start() } diff --git a/git/git.go b/routes/git/git.go similarity index 100% rename from git/git.go rename to routes/git/git.go diff --git a/git/post.go b/routes/git/post.go similarity index 97% rename from git/post.go rename to routes/git/post.go index f9e1f152..259abb99 100644 --- a/git/post.go +++ b/routes/git/post.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/hacdias/caddy-hugo/config" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/utils" ) // POST handles the POST method on GIT page which is only an API. diff --git a/tools/commands/commands.go b/tools/commands/commands.go new file mode 100644 index 00000000..7e8056c8 --- /dev/null +++ b/tools/commands/commands.go @@ -0,0 +1,15 @@ +package commands + +import ( + "os" + "os/exec" +) + +// RunCommand executes an external command +func Run(command string, args []string, path string) error { + cmd := exec.Command(command, args...) + cmd.Dir = path + cmd.Stdout = os.Stderr + cmd.Stderr = os.Stderr + return cmd.Run() +} diff --git a/tools/files/files.go b/tools/files/files.go new file mode 100644 index 00000000..084259ca --- /dev/null +++ b/tools/files/files.go @@ -0,0 +1,30 @@ +package files + +import ( + "io" + "os" +) + +// CopyFile is used to copy a file +func CopyFile(old, new string) error { + // Open the file and create a new one + r, err := os.Open(old) + if err != nil { + return err + } + defer r.Close() + + w, err := os.Create(new) + if err != nil { + return err + } + defer w.Close() + + // Copy the content + _, err = io.Copy(w, r) + if err != nil { + return err + } + + return nil +} diff --git a/tools/files/files_test.go b/tools/files/files_test.go new file mode 100644 index 00000000..d7a01d97 --- /dev/null +++ b/tools/files/files_test.go @@ -0,0 +1,11 @@ +package files + +import "testing" + +func TestCopyFile(t *testing.T) { + err := CopyFile("test_data/file_to_copy.txt", "test_data/copied_file.txt") + + if err != nil { + t.Error("Can't copy the file.") + } +} diff --git a/utils/test_data/file_to_copy.txt b/tools/files/test_data/file_to_copy.txt similarity index 100% rename from utils/test_data/file_to_copy.txt rename to tools/files/test_data/file_to_copy.txt diff --git a/frontmatter/frontmatter.go b/tools/frontmatter/frontmatter.go similarity index 97% rename from frontmatter/frontmatter.go rename to tools/frontmatter/frontmatter.go index 77bd7524..c787c503 100644 --- a/frontmatter/frontmatter.go +++ b/tools/frontmatter/frontmatter.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/hacdias/caddy-hugo/utils" + "github.com/hacdias/caddy-hugo/tools/types" "github.com/spf13/cast" "github.com/spf13/hugo/parser" ) @@ -60,9 +60,9 @@ func rawToPretty(config interface{}, parent *frontmatter) interface{} { } for name, element := range cnf { - if utils.IsMap(element) { + if types.IsMap(element) { objects = append(objects, handleObjects(element, parent, name)) - } else if utils.IsSlice(element) { + } else if types.IsSlice(element) { arrays = append(arrays, handleArrays(element, parent, name)) } else { if name == "title" && parent.Name == mainName { diff --git a/hugo/hugo.go b/tools/hugo/hugo.go similarity index 90% rename from hugo/hugo.go rename to tools/hugo/hugo.go index 4764ed11..966935cb 100644 --- a/hugo/hugo.go +++ b/tools/hugo/hugo.go @@ -13,6 +13,7 @@ import ( "path/filepath" "runtime" + "github.com/hacdias/caddy-hugo/config" "github.com/mitchellh/go-homedir" "github.com/pivotal-golang/archiver/extractor" ) @@ -44,6 +45,35 @@ var ( } ) +// Run is used to run the static website generator +func Run(c *config.Config, force bool) { + os.RemoveAll(c.Path + "public") + + // Prevent running if watching is enabled + if b, pos := stringInSlice("--watch", c.Args); b && !force { + if len(c.Args) > pos && c.Args[pos+1] != "false" { + return + } + + if len(c.Args) == pos+1 { + return + } + } + + if err := RunCommand(c.Hugo, c.Args, c.Path); err != nil { + log.Panic(err) + } +} + +func stringInSlice(a string, list []string) (bool, int) { + for i, b := range list { + if b == a { + return true, i + } + } + return false, 0 +} + // GetPath retrives the Hugo path for the user or install it if it's not found func GetPath() string { initializeVariables() @@ -126,9 +156,9 @@ func GetPath() string { fmt.Println(err) os.Exit(-1) } - + err = os.Chmod(hugo, 0755) - + if err != nil { fmt.Println(err) os.Exit(-1) diff --git a/utils/utils.go b/tools/templates/templates.go similarity index 52% rename from utils/utils.go rename to tools/templates/templates.go index c3396ba4..18f9b309 100644 --- a/utils/utils.go +++ b/tools/templates/templates.go @@ -1,20 +1,15 @@ -package utils +package templates import ( - "encoding/json" "errors" - "io" + "html/template" "log" "net/http" - "os" - "os/exec" "reflect" "strings" - "text/template" "unicode" "github.com/hacdias/caddy-hugo/assets" - "github.com/hacdias/caddy-hugo/config" ) // CanBeEdited checks if the extension of a file is supported by the editor @@ -39,30 +34,6 @@ func CanBeEdited(filename string) bool { return false } -// CopyFile is used to copy a file -func CopyFile(old, new string) error { - // Open the file and create a new one - r, err := os.Open(old) - if err != nil { - return err - } - defer r.Close() - - w, err := os.Create(new) - if err != nil { - return err - } - defer w.Close() - - // Copy the content - _, err = io.Copy(w, r) - if err != nil { - return err - } - - return nil -} - // Defined checks if variable is defined in a struct func Defined(data interface{}, field string) bool { t := reflect.Indirect(reflect.ValueOf(data)).Type() @@ -93,9 +64,9 @@ func Dict(values ...interface{}) (map[string]interface{}, error) { return dict, nil } -// GetTemplate is used to get a ready to use template based on the url and on +// Get is used to get a ready to use template based on the url and on // other sent templates -func GetTemplate(r *http.Request, functions template.FuncMap, templates ...string) (*template.Template, error) { +func Get(r *http.Request, functions template.FuncMap, templates ...string) (*template.Template, error) { // If this is a pjax request, use the minimal template to send only // the main content if r.Header.Get("X-PJAX") == "true" { @@ -134,74 +105,6 @@ func GetTemplate(r *http.Request, functions template.FuncMap, templates ...strin return tpl, nil } -// IsMap checks if some variable is a map -func IsMap(sth interface{}) bool { - return reflect.ValueOf(sth).Kind() == reflect.Map -} - -// IsSlice checks if some variable is a slice -func IsSlice(sth interface{}) bool { - return reflect.ValueOf(sth).Kind() == reflect.Slice -} - -// ParseComponents parses the components of an URL creating an array -func ParseComponents(r *http.Request) []string { - //The URL that the user queried. - path := r.URL.Path - path = strings.TrimSpace(path) - //Cut off the leading and trailing forward slashes, if they exist. - //This cuts off the leading forward slash. - if strings.HasPrefix(path, "/") { - path = path[1:] - } - //This cuts off the trailing forward slash. - if strings.HasSuffix(path, "/") { - cutOffLastCharLen := len(path) - 1 - path = path[:cutOffLastCharLen] - } - //We need to isolate the individual components of the path. - components := strings.Split(path, "/") - return components -} - -// Run is used to run the static website generator -func Run(c *config.Config, force bool) { - os.RemoveAll(c.Path + "public") - - // Prevent running if watching is enabled - if b, pos := stringInSlice("--watch", c.Args); b && !force { - if len(c.Args) > pos && c.Args[pos+1] != "false" { - return - } - - if len(c.Args) == pos+1 { - return - } - } - - if err := RunCommand(c.Hugo, c.Args, c.Path); err != nil { - log.Panic(err) - } -} - -// RunCommand executes an external command -func RunCommand(command string, args []string, path string) error { - cmd := exec.Command(command, args...) - cmd.Dir = path - cmd.Stdout = os.Stderr - cmd.Stderr = os.Stderr - return cmd.Run() -} - -func stringInSlice(a string, list []string) (bool, int) { - for i, b := range list { - if b == a { - return true, i - } - } - return false, 0 -} - var splitCapitalizeExceptions = map[string]string{ "youtube": "YouTube", "github": "GitHub", @@ -237,20 +140,3 @@ func SplitCapitalize(name string) string { return name } - -func RespondJSON(w http.ResponseWriter, message map[string]string, code int, err error) (int, error) { - msg, msgErr := json.Marshal(message) - - if msgErr != nil { - return 500, msgErr - } - - if code == 500 && err != nil { - err = errors.New(message["message"]) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(code) - w.Write(msg) - return 0, err -} diff --git a/utils/utils_test.go b/tools/templates/templates_test.go similarity index 91% rename from utils/utils_test.go rename to tools/templates/templates_test.go index 13df32d5..a9173669 100644 --- a/utils/utils_test.go +++ b/tools/templates/templates_test.go @@ -1,4 +1,4 @@ -package utils +package templates import "testing" @@ -38,14 +38,6 @@ func TestCanBeEdited(t *testing.T) { } } -func TestCopyFile(t *testing.T) { - err := CopyFile("test_data/file_to_copy.txt", "test_data/copied_file.txt") - - if err != nil { - t.Error("Can't copy the file.") - } -} - type testDefinedData struct { f1 string f2 bool diff --git a/tools/types/types.go b/tools/types/types.go new file mode 100644 index 00000000..2de62cf5 --- /dev/null +++ b/tools/types/types.go @@ -0,0 +1,13 @@ +package types + +import "reflect" + +// IsMap checks if some variable is a map +func IsMap(sth interface{}) bool { + return reflect.ValueOf(sth).Kind() == reflect.Map +} + +// IsSlice checks if some variable is a slice +func IsSlice(sth interface{}) bool { + return reflect.ValueOf(sth).Kind() == reflect.Slice +} diff --git a/tools/utils/utils.go b/tools/utils/utils.go new file mode 100644 index 00000000..eadc6014 --- /dev/null +++ b/tools/utils/utils.go @@ -0,0 +1,45 @@ +package utils + +import ( + "encoding/json" + "errors" + "net/http" + "strings" +) + +// ParseComponents parses the components of an URL creating an array +func ParseComponents(r *http.Request) []string { + //The URL that the user queried. + path := r.URL.Path + path = strings.TrimSpace(path) + //Cut off the leading and trailing forward slashes, if they exist. + //This cuts off the leading forward slash. + if strings.HasPrefix(path, "/") { + path = path[1:] + } + //This cuts off the trailing forward slash. + if strings.HasSuffix(path, "/") { + cutOffLastCharLen := len(path) - 1 + path = path[:cutOffLastCharLen] + } + //We need to isolate the individual components of the path. + components := strings.Split(path, "/") + return components +} + +func RespondJSON(w http.ResponseWriter, message map[string]string, code int, err error) (int, error) { + msg, msgErr := json.Marshal(message) + + if msgErr != nil { + return 500, msgErr + } + + if code == 500 && err != nil { + err = errors.New(message["message"]) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(code) + w.Write(msg) + return 0, err +} diff --git a/utils/test_data/copied_file.txt b/utils/test_data/copied_file.txt deleted file mode 100644 index a5e04363..00000000 --- a/utils/test_data/copied_file.txt +++ /dev/null @@ -1,9 +0,0 @@ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin faucibus augue vel ex auctor molestie. Sed id lorem quis velit eleifend vestibulum. Etiam tincidunt nulla et metus dictum imperdiet. Suspendisse ac auctor risus. Donec tempus eros quis erat interdum fringilla. Duis ac tristique lorem, quis vulputate enim. In ut est elementum, dignissim tellus quis, ultrices diam. Aenean in efficitur velit, ut imperdiet felis. Suspendisse aliquet accumsan ligula, a iaculis sem luctus vel. Integer sagittis, orci viverra lacinia efficitur, eros magna sodales sapien, in tristique ante arcu ut nunc. Maecenas odio dolor, semper quis vehicula ut, malesuada sollicitudin massa. Integer dolor ligula, hendrerit convallis quam at, luctus dignissim nibh. Fusce interdum congue justo, at imperdiet lorem maximus in. - -Curabitur dignissim id turpis ut eleifend. Pellentesque vehicula et purus et consectetur. Nulla facilisis vehicula nunc in imperdiet. Nam eget porta libero, vel dapibus leo. Maecenas iaculis, arcu quis vehicula sollicitudin, massa tortor mattis tortor, vitae venenatis erat neque et dui. Mauris eleifend vel urna ac interdum. Sed convallis, arcu et scelerisque suscipit, nulla urna laoreet mauris, quis aliquam dolor elit id mauris. Pellentesque ac pulvinar nibh. Duis vestibulum ligula orci, et mattis turpis facilisis mattis. Vivamus feugiat neque sed aliquet aliquet. Sed consequat augue sagittis eros imperdiet, ac lacinia erat tempor. Cras gravida mi a orci euismod feugiat. Mauris condimentum turpis id quam vulputate, et maximus dolor hendrerit. - -Ut nisi urna, sollicitudin ac facilisis eu, rhoncus sed urna. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla eu maximus mi, sed commodo diam. Nunc scelerisque tincidunt ipsum eget mattis. Fusce id finibus nisi, sit amet tempus tortor. Fusce accumsan lectus at dignissim volutpat. Nullam nisl nulla, rhoncus id arcu vitae, eleifend posuere libero. Aliquam dictum bibendum bibendum. Integer non mattis neque. Phasellus fermentum et ex vel vehicula. - -Proin eget ligula lorem. Ut vehicula quis augue sed aliquet. Nulla viverra turpis nulla. Morbi et ipsum odio. Nulla in nisi suscipit justo blandit tristique ac vitae ipsum. Donec viverra dictum arcu. Duis est elit, ultrices a massa non, lobortis maximus eros. Nulla porttitor rhoncus lectus in finibus. Duis convallis sapien porta, fringilla orci nec, ultricies nisl. Morbi pulvinar quam in nulla rutrum euismod. - -Donec et accumsan lectus, consectetur posuere nunc. Quisque et quam hendrerit, vestibulum quam eget, luctus enim. In hac habitasse platea dictumst. Nunc et est scelerisque, bibendum neque quis, ornare elit. Aliquam erat volutpat. Nulla maximus nibh vitae ex interdum, a efficitur lacus eleifend. Nam vestibulum blandit aliquet. In hac habitasse platea dictumst. Maecenas interdum quam et lorem posuere interdum. Mauris id feugiat augue. Etiam vestibulum pharetra cursus.