diff --git a/TxtStore.go b/TxtStore.go
new file mode 100644
index 0000000..36f5f19
--- /dev/null
+++ b/TxtStore.go
@@ -0,0 +1,56 @@
+package main
+
+import (
+ "bufio"
+ "os"
+)
+
+type TxtStore string
+
+func (t *TxtStore) GetGuestbook() (Guestbook, error) {
+ var result Guestbook
+
+ file, err := os.Open(string(*t))
+ if os.IsNotExist(err) {
+ return result, nil
+ } else if err != nil {
+ return result, err
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ var comments []string
+
+ for scanner.Scan() {
+ comments = append([]string{scanner.Text()}, comments...)
+ }
+
+ err = scanner.Err()
+ if err != nil {
+ return result, err
+ }
+
+ result.Comments = comments
+ result.Count = len(comments)
+
+ return result, nil
+}
+
+func (t *TxtStore) AddComment(comment string) error {
+ if comment == "" {
+ return nil
+ }
+
+ options := os.O_WRONLY | os.O_APPEND | os.O_CREATE
+ file, err := os.OpenFile(string(*t), options, os.FileMode(0600))
+ if err != nil {
+ return err
+ }
+
+ _, err = file.WriteString(comment + "\n")
+ if err != nil {
+ return err
+ }
+
+ return file.Close()
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..7e15a5a
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module git.atik.me/guestbook
+
+go 1.16
diff --git a/html/favicon.png b/html/favicon.png
new file mode 100644
index 0000000..8847396
Binary files /dev/null and b/html/favicon.png differ
diff --git a/html/index.html b/html/index.html
new file mode 100644
index 0000000..14390d7
--- /dev/null
+++ b/html/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
Книга отзывов
+
+
+
+
+
+ {{ range .Comments }}- {{ . }}
{{ end}}
+
+
+
+
diff --git a/html/styles.css b/html/styles.css
new file mode 100644
index 0000000..f10e160
--- /dev/null
+++ b/html/styles.css
@@ -0,0 +1,79 @@
+* {
+ margin: 0;
+ padding: 0;
+
+ font-family: 'Raleway', serif;
+}
+
+body {
+ padding: 1%;
+
+ color: #2E3E50;
+ background: #D8DDDD;
+
+ text-align: center;
+ letter-spacing: 1px;
+}
+
+.main {
+ margin: auto;
+ padding: 1% 2%;
+ max-width: 800px;
+ border-radius: 5px;
+ background: #ECF0F1;
+ box-shadow: 0 2px 6px 0 rgba(0, 0, 0, .3);
+}
+
+form {
+ width: 100%;
+ display: flex;
+ margin: 2% 0;
+
+}
+
+form p {
+ text-align: left;
+ padding: 1%;
+ font-size: 18px;
+}
+
+input {
+ padding: 1%;
+ border-radius: 4px;
+ border: 1px solid #CCC;
+ font-size: 18px;
+}
+
+input[type=text] {
+ flex-grow: 1;
+
+ margin: 0 .5%;
+}
+
+input[type=submit] {
+ cursor: pointer;
+}
+
+input[type=submit]:hover {
+ background-color: #D8DDDD;
+}
+
+h1 {
+ font-family: 'Baloo Tamma', cursive;
+}
+
+li{
+ list-style-type: none;
+
+ font-size: 18px;
+ min-width: 24%;
+ margin: 2% 0;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
+ padding: 1% 2%;
+ background: #FFF;
+ box-sizing: border-box;
+}
+
+li:hover {
+ box-shadow:0 5px 10px rgba(0, 0, 0, .15);
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..588c217
--- /dev/null
+++ b/main.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "html/template"
+ "log"
+ "net/http"
+)
+
+type Guestbook struct {
+ Comments []string
+ Count int
+}
+
+func indexHandler(writer http.ResponseWriter, request *http.Request) {
+ html, err := template.ParseFiles("html/index.html")
+ check(err)
+
+ store := TxtStore("comments.txt")
+ guestbook, err := store.GetGuestbook()
+ check(err)
+
+ err = html.Execute(writer, guestbook)
+ check(err)
+}
+
+func newHandler(writer http.ResponseWriter, request *http.Request) {
+ comment := request.FormValue("comment")
+ store := TxtStore("comments.txt")
+
+ err := store.AddComment(comment)
+ check(err)
+
+ http.Redirect(writer, request, "/", http.StatusFound)
+}
+
+func main() {
+ http.HandleFunc("/", indexHandler)
+ http.HandleFunc("/new", newHandler)
+
+ http.Handle("/html/", http.StripPrefix("/html/", http.FileServer(http.Dir("html"))))
+
+ err := http.ListenAndServe("0.0.0.0:80", nil)
+ log.Fatal(err)
+}
+
+func check(err error) {
+ if err != nil {
+ log.Fatal(err)
+ }
+}