commit 77f1d417c98929d98d51819263e58385fc99da1e Author: Bas Kloosterman Date: Mon May 2 16:26:06 2022 +0200 Initial commit diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5a89119 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.git +data +run +bin +nginx +dist + +.DS_Store +._.DS_Store +node_modules +package-lock.json + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40efffe --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.DS_Store +._.DS_Store +node_modules +package-lock.json +dist/* +bin/* +data/db/data.db +nginx/flip_cohen.conf +data/config/config.yaml +dockercompose/* +!dockercompose/docker-compose.yaml +!.keep \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..03d6043 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# syntax=docker/dockerfile:1 + +## +## Build +## +FROM golang:alpine AS build + +WORKDIR /app + +RUN apk update +RUN apk add --update gcc g++ +RUN apk add --update python3 +RUN apk add --update npm + +COPY package.json ./package.json +RUN npm i + +COPY ./src ./src +COPY ./gulpfile.js ./gulpfile.js +COPY ./webpack.config.js ./webpack.config.js +RUN npx gulp build + +COPY go.mod . +COPY go.sum . +RUN go mod download +RUN go install github.com/mattn/go-sqlite3 + +COPY . ./ +RUN ls -l +RUN mkdir bin +RUN go build -o bin/thomasshop + +## +## Deploy +## +FROM alpine:latest + +WORKDIR / + +COPY --from=build /app/bin/thomasshop /bin +COPY --from=build /app/dist /dist +COPY --from=build /app/templates /templates +RUN echo "#!/bin/ash" > /run.sh +RUN echo "cp -r /dist/* /outdist" >> /run.sh +RUN echo "exec /bin/thomasshop" >> /run.sh +RUN chmod +x /run.sh + +ENTRYPOINT ["/run.sh"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fc970bc --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +.PHONY: all clean config + +all: bin/site_flip dist/js/shared.js dist/css/index.css config + +bin/site_flip: main.go events.go albums.go + go build main.go events.go albums.go && mv main bin/site_flip + +dist/js/shared.js: $(wildcard src/js/*.js src/js/*/*.js) + NODE_ENV=production gulp build + +dist/css/index.css: $(wildcard src/sass/*.scss src/sass/*/*.scss) + NODE_ENV=production gulp build + +config: nginx/flip_cohen.conf + +nginx/flip_cohen.conf: nginx/template.conf + ./init.sh `pwd` + +clean: + rm -f nginx/flip_cohen.conf + rm -f bin/site_flip diff --git a/albums.go b/albums.go new file mode 100644 index 0000000..dd2ab2c --- /dev/null +++ b/albums.go @@ -0,0 +1,152 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "strings" +) + +type Song struct { + Title string + Lyrics []string + Path string + NR string +} + +type Album struct { + Name string + Release string + Path string + Songs []Song + Links map[string]string +} + +const ALBUM_DIR = "./data/albums/" + +var albums []*Album + +func parseAlbumName(fName string) (string, string) { + s := strings.Split(fName, ".") + s = strings.Split(s[0], "_") + + return s[0], strings.Join(s[1:], " ") +} + +func ParseSong(s os.FileInfo, basePath string) Song { + nr, title := parseAlbumName(s.Name()) + + f, err := os.Open(path.Join(basePath, s.Name())) + defer f.Close() + + if err != nil { + log.Fatal(err) + } + + content, err := ioutil.ReadAll(f) + + if err != nil { + log.Fatal(err) + } + + lyrics := strings.Split(string(content), "\n\n") + + song := Song{ + Title: title, + Lyrics: lyrics, + Path: strings.ToLower(strings.Replace(title, " ", "-", -1)), + NR: nr, + } + + return song +} + +func getSong(album *Album, title string) (Song, error) { + for _, song := range album.Songs { + if song.Path == strings.ToLower(title) { + return song, nil + } + } + + return Song{}, io.EOF +} + +func ParseAlbum(f os.FileInfo) *Album { + year, name := parseAlbumName(f.Name()) + + filen := path.Join(ROOT_DIR, ALBUM_DIR, f.Name()) + + files, err := ioutil.ReadDir(filen) + + if err != nil { + fmt.Printf("Error read songs: %s", err) + log.Fatal(err) + } + + album := Album{ + Name: name, + Path: strings.ToLower(strings.Replace(name, " ", "-", -1)), + Release: year, + } + + for _, f := range files { + if !strings.HasSuffix(f.Name(), ".lyric") { + continue + } + album.Songs = append(album.Songs, ParseSong(f, filen)) + } + + fd, err := os.Open(path.Join(filen, "info.json")) + defer fd.Close() + + if err != nil { + fmt.Printf("Error info.json: %s", err) + log.Fatal(err) + } + + content, _ := ioutil.ReadAll(fd) + + json.Unmarshal(content, &album) + + return &album +} + +func getAlbum(albums []*Album, title string) (*Album, error) { + for _, album := range albums { + if album.Path == strings.ToLower(title) { + return album, nil + } + } + + return nil, io.EOF +} + +func getAlbums() []*Album { + if albums != nil { + return albums + } + + files, err := ioutil.ReadDir(path.Join(ROOT_DIR, ALBUM_DIR)) + + if err != nil { + log.Fatal(err) + } + + for _, f := range files { + if strings.HasPrefix(f.Name(), ".") { + continue + } + albums = append(albums, ParseAlbum(f)) + } + + for i := len(albums)/2 - 1; i >= 0; i-- { + opp := len(albums) - 1 - i + albums[i], albums[opp] = albums[opp], albums[i] + } + + return albums +} diff --git a/data/config/.keep b/data/config/.keep new file mode 100644 index 0000000..e69de29 diff --git a/data/db/.keep b/data/db/.keep new file mode 100644 index 0000000..e69de29 diff --git a/db.go b/db.go new file mode 100644 index 0000000..4fb174c --- /dev/null +++ b/db.go @@ -0,0 +1,136 @@ +package main + +import ( + "fmt" + "log" + "os" + "path" + "time" + + uuid "github.com/satori/go.uuid" + + sqlite "gorm.io/driver/sqlite" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +const ( + PRE_ORDER_STATE_CREATED = "CREATED" +) + +func initDB() (*gorm.DB, error) { + log.Printf("Connect to DB on path: %v", path.Join(ROOT_DIR, "data/db/data.db")) + + newLogger := logger.New( + log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer + logger.Config{ + SlowThreshold: time.Second, // Slow SQL threshold + LogLevel: logger.Info, // Log level + Colorful: false, // Disable color + }, + ) + + db, err := gorm.Open(sqlite.Open(path.Join(ROOT_DIR, "data/db/data.db")), &gorm.Config{ + Logger: newLogger, + }) + return db, err +} + +type Product struct { + gorm.Model + Name string + Image string + Description string + Price int +} + +type Item struct { + gorm.Model + ProductID uint + Product Product + PreOrderID uuid.UUID + PreOrder PreOrder +} + +type MolliePayment struct { + gorm.Model + MolliePaymentID string + Amount int + Status string + PreOrderID uuid.UUID + PreOrder PreOrder +} + +type PreOrder struct { + ID uuid.UUID `sql:"type:string;primary_key;"` + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time `sql:"index"` + Name string + Email string + Items []Item + Address string + Postcode string + City string + Country string + Status string + MolliePayments []MolliePayment +} + +var nullUUID = uuid.UUID{} + +func (base *PreOrder) BeforeCreate(scope *gorm.DB) error { + fmt.Println(base.ID.String(), nullUUID.String()) + if base.ID.String() == nullUUID.String() { + id := uuid.NewV4() + base.ID = id + } + return nil +} + +func (po *PreOrder) CalcTotal() int { + total := 0 + + for _, i := range po.Items { + total += i.Product.Price + } + + return total +} + +func insertProducts(db *gorm.DB) { + db.Create(&Product{ + Name: "Methods to Madness | LP", + Image: "/static/img/mtm.jpg", + Description: "Methods to Madness LP", + Price: 2999, + }) + + db.Create(&Product{ + Name: "Methods to Madness | CD", + Image: "/static/img/mtm.jpg", + Description: "Methods to Madness CD", + Price: 1999, + }) +} + +func GetDB() *gorm.DB { + db, err := initDB() + + if err != nil { + panic("failed to connect database") + } + + // Migrate the schema + db.AutoMigrate( + &Product{}, + &Item{}, + &PreOrder{}, + &MolliePayment{}, + ) + + products := []Product{} + db.Find(&products) + + return db +} diff --git a/dist/.keep b/dist/.keep new file mode 100644 index 0000000..e69de29 diff --git a/dockercompose/docker-compose.yaml b/dockercompose/docker-compose.yaml new file mode 100644 index 0000000..16b1e1d --- /dev/null +++ b/dockercompose/docker-compose.yaml @@ -0,0 +1,18 @@ +version: '3.0' +services: + alex: + image: dregistry.baskloosterman.nl:5000/thomasshop + container_name: thomasshop + restart: always + volumes: + - "./thomas/data:/data" + - "./thomas/dist:/outdist" + nginx: + image: nginx:alpine + container_name: nginx_thomas + restart: always + volumes: + - "./thomas/nginx:/etc/nginx/conf.d" + - "./thomas/dist:/var/www/thomas/dist" + ports: + - "3999:80" diff --git a/events.go b/events.go new file mode 100644 index 0000000..3812e6e --- /dev/null +++ b/events.go @@ -0,0 +1,185 @@ +package main + +import ( + "bufio" + "encoding/csv" + "encoding/json" + "fmt" + "io" + "log" + "os" + "path" + "sort" + "strings" + "time" +) + +type MyTime time.Time + +func (mt *MyTime) UnmarshalJSON(b []byte) error { + s := strings.Trim(string(b), "\"") + t, err := time.Parse("2006-01-02", s) + if err != nil { + return err + } + *mt = MyTime(t) + return nil +} + +func ParseDate(b string) MyTime { + s := strings.Trim(b, "\"") + t, err := time.Parse("2006-01-02", s) + if err != nil { + return MyTime{} + } + return MyTime(t) +} + +func (mt *MyTime) ParseDate(b []byte) error { + s := strings.Trim(string(b), "\"") + t, err := time.Parse("2006-01-02", s) + if err != nil { + return err + } + *mt = MyTime(t) + return nil +} + +func (mt MyTime) MarshalJSON() ([]byte, error) { + return json.Marshal(mt) +} + +var months = map[string]string{ + "1": "Jan", + "2": "Feb", + "3": "Mrt", + "4": "Apr", + "5": "Mei", + "6": "Jun", + "7": "Jul", + "8": "Aug", + "9": "Sept", + "10": "Okt", + "11": "Nov", + "12": "Dec", +} + +var monthsLong = map[string]string{ + "1": "Januari", + "2": "Februari", + "3": "Maart", + "4": "April", + "5": "Mei", + "6": "Juni", + "7": "July", + "8": "Augustus", + "9": "September", + "10": "Oktober", + "11": "November", + "12": "December", +} + +func (mt MyTime) Format() string { + t := time.Time(mt) + return fmt.Sprintf("%v %v %v", t.Format("Jan"), t.Format("02"), t.Format("2006")) +} + +func (mt MyTime) Title() string { + t := time.Time(mt) + return fmt.Sprintf("%v %v", t.Format("Januari"), t.Format("2006")) +} + +type EventFlags struct { + Soldout bool + Tryout bool + Premiere bool + Preview bool + XL bool + Solo bool +} + +type Event struct { + Date MyTime `json:"date"` + Venue string `json:"venue"` + City string `json:"city"` + Link string `json:"link"` + Time string `json:"time"` + Title string `json:"title"` + Flags EventFlags `json:"flags"` +} + +func (e *Event) SetFlags(flags string) { + for _, flag := range strings.Split(flags, ",") { + switch strings.Trim(strings.ToLower(flag), " \t") { + case "uitverkocht": + e.Flags.Soldout = true + case "tryout": + e.Flags.Tryout = true + case "preview": + e.Flags.Preview = true + case "premiere": + e.Flags.Premiere = true + case "solo": + e.Flags.Solo = true + case "xl": + e.Flags.XL = true + } + } +} + +func getEvents() *[]Event { + var events []Event + + f, err := os.Open(path.Join(ROOT_DIR, "data/events.csv")) + if err != nil { + log.Fatal(err) + } + + defer f.Close() + + reader := csv.NewReader(bufio.NewReader(f)) + reader.Comma = ';' + + now := time.Now() + + for { + line, error := reader.Read() + if error == io.EOF { + break + } else if error != nil { + log.Fatal(error) + } + + if line[0] == "date" { + continue + } + + if now.After( + (time.Time(ParseDate(line[0]))).Local().Add(time.Hour * time.Duration(24)), + ) { + continue + } + + event := Event{ + Date: ParseDate(line[0]), + Time: line[1], + City: line[2], + Title: line[3], + Venue: line[4], + Link: line[5], + } + + event.SetFlags(line[6]) + + events = append(events, event) + } + + sort.SliceStable(events, func(i, j int) bool { + a := events[i] + b := events[j] + + return time.Time(a.Date).Before(time.Time(b.Date)) + }) + + return &events +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..63f86fc --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module gitea.basklooosterman.nl/thomasshop + +go 1.13 + +require ( + github.com/VictorAvelar/mollie-api-go v1.6.6 // indirect + github.com/VictorAvelar/mollie-api-go/v3 v3.1.2 // indirect + github.com/gin-contrib/multitemplate v0.0.0-20220323084503-710510e67c20 + github.com/gin-gonic/gin v1.7.7 + github.com/satori/go.uuid v1.2.0 + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect + gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/yaml.v2 v2.4.0 + gorm.io/driver/sqlite v1.3.1 + gorm.io/gorm v1.23.4 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4816cfb --- /dev/null +++ b/go.sum @@ -0,0 +1,469 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/VictorAvelar/mollie-api-go v1.6.6 h1:VWP+k0PRt6esWO8qbCMO/ZvIRDrhBonkt0kxYEnGugk= +github.com/VictorAvelar/mollie-api-go v1.6.6/go.mod h1:ndE8MbwgUZoq827yh0ppyYncii5jZLa0acL6j5iqZyk= +github.com/VictorAvelar/mollie-api-go/v3 v3.1.2 h1:uDtk4yMcehQflUkugqds9HQ6bBjV7a6Wjy9DMhWV9R0= +github.com/VictorAvelar/mollie-api-go/v3 v3.1.2/go.mod h1:/twx+AOJSjclpc9yaUHFrCxET9ad6y0nlH0HOMOT38Q= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/gin-contrib/multitemplate v0.0.0-20211002122701-e9e3201b87a0 h1:5Ot5t4hgu/lhNzwbJhxEq3gsoHUf/C7yX4P1jZcJWO0= +github.com/gin-contrib/multitemplate v0.0.0-20211002122701-e9e3201b87a0/go.mod h1:V2h3mKlTX44jWIvsJ6KDOq808yu3dws0qosCjP9Q7nY= +github.com/gin-contrib/multitemplate v0.0.0-20220323084503-710510e67c20 h1:R8oLt08so7CFl7DHJDfNgWSgpf6iFCbjmUdJiepbbNU= +github.com/gin-contrib/multitemplate v0.0.0-20220323084503-710510e67c20/go.mod h1:V2h3mKlTX44jWIvsJ6KDOq808yu3dws0qosCjP9Q7nY= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= +github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c h1:dk0ukUIHmGHqASjP0iue2261isepFCC6XRCSd1nHgDw= +golang.org/x/net v0.0.0-20201002202402-0a1ea396d57c/go.mod h1:iQL9McJNjoIa5mjH6nYTCTZXUN6RP+XW3eib7Ya3XcI= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225143145-3bcbab3f74ef/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= +gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= +gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= +gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= +gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk= +gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg= +gorm.io/gorm v1.22.3/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= +gorm.io/gorm v1.22.4 h1:8aPcyEJhY0MAt8aY6Dc524Pn+pO29K+ydu+e/cXSpQM= +gorm.io/gorm v1.22.4/go.mod h1:1aeVC+pe9ZmvKZban/gW4QPra7PRoTEssyc922qCAkk= +gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.4 h1:1BKWM67O6CflSLcwGQR7ccfmC4ebOxQrTfOQGRE9wjg= +gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..0104ab9 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,68 @@ +const gulp = require('gulp'); +// const sass = require('gulp-sass'); +const sass = require('gulp-sass')(require('sass')); +const webpack = require('webpack'); +const webpackStream = require('webpack-stream'); +const config = require('./webpack.config'); + +const cleanCSS = require('gulp-clean-css'); +const autoprefixer = require('gulp-autoprefixer'); + +const newer = require('gulp-newer'); + +const fontsSrc = './src/fonts' +const fontsDest = './dist/fonts' + +const imgSrc = './src/img' +const imgDest = './dist/img' + +const downloadSrc = './src/download' +const downloadDest = './dist/download' + +const sassTask = () => { + return gulp.src('./src/sass/**/*.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefixer({ + browsers: ['last 2 versions', 'ie > 8'], + cascade: false + })) + .pipe(cleanCSS({compatibility: 'ie8'})) + .pipe(gulp.dest('./dist/css')); +} + +const jsTask =() => { + return gulp.src('./src/js/shared.js') + .pipe(webpackStream(config, webpack)) + .pipe(gulp.dest('./dist/js/')); +} + +const fontsTask = () => { + return gulp.src(`./${fontsSrc}/**`) + .pipe(newer(fontsDest)) + .pipe(gulp.dest(fontsDest)); +} + +const imgTask = () => { + return gulp.src(`./${imgSrc}/**`) + // .pipe(newer(imgDest)) + .pipe(gulp.dest(imgDest)); +} + +const downloadTask = () => { + return gulp.src(`./${downloadSrc}/**`) + // .pipe(newer(downloadDest)) + .pipe(gulp.dest(downloadDest)); +} + +const watch = () => { + gulp.watch('./src/sass/**/*.scss', sassTask); + gulp.watch('./src/fonts/**', fontsTask); + gulp.watch('./src/img/**', imgTask); +} + +const build = gulp.parallel(jsTask, gulp.series(sassTask, fontsTask, imgTask, downloadTask)); +module.exports = { + default: gulp.parallel(jsTask, gulp.series(sassTask, fontsTask, imgTask, watch)), + build +} + diff --git a/init.sh b/init.sh new file mode 100755 index 0000000..5553e33 --- /dev/null +++ b/init.sh @@ -0,0 +1,7 @@ +#! /bin/sh + + +echo "Enter fqdn:" +read host_name + +sed "s#{{root_dir}}#$1#g;s#{{host_name}}#$2#g" nginx/template.conf > nginx/flip_cohen.conf \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..23ecbbb --- /dev/null +++ b/main.go @@ -0,0 +1,213 @@ +package main + +import ( + "fmt" + "html/template" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "os/signal" + "path" + "time" + + "github.com/VictorAvelar/mollie-api-go/v3/mollie" + "github.com/gin-contrib/multitemplate" + + "github.com/gin-gonic/gin" + yaml "gopkg.in/yaml.v2" + "gorm.io/gorm" +) + +// var SOCKNAME = "thomas.sock" +var addr = "0.0.0.0:3000" + +type Config struct { + MollieToken string `yaml:"mollie_token"` + MollieTesting bool `yaml:"mollie_testing"` + MollieWebhook string `yaml:"mollie_webhook"` + MollieRedirectURL string `yaml:"mollie_redirect_url"` + MailServer string `yaml:"mail_server"` + MailPort int `yaml:"mail_port"` + MailUser string `yaml:"mail_user"` + MailPass string `yaml:"mail_pass"` + FromAddr string `yaml:"from_addr"` + BCC string `yaml:"bcc"` +} + +var config Config + +var mollieClient *mollie.Client + +var ROOT_DIR string + +func notFound(w http.ResponseWriter, r *http.Request) error { + w.WriteHeader(http.StatusNotFound) + + t, err := template.ParseFiles(path.Join(ROOT_DIR, "templates/404.html")) + + if err != nil { + return err + } + + return t.Execute(w, nil) +} + +func index(c *gin.Context) { + db := getDB(c) + + products := []Product{} + + db.Order("id desc").Find(&products) + + c.HTML(http.StatusOK, "index", map[string]interface{}{ + "products": products, + }) +} + +func handle404(c *gin.Context) { + c.HTML(http.StatusOK, "404.html", map[string]interface{}{}) +} + +func createSocket(s string) net.Listener { + os.Remove(s) + + log.Println("Creating UNIX socket:", s) + sock, err := net.Listen("unix", s) + if err != nil { + panic(err) + } + + err = os.Chmod(s, 0777) + + if err != nil { + panic(err) + } + + return sock +} + +func getDB(c *gin.Context) *gorm.DB { + item, _ := c.Get("db") + db := item.(*gorm.DB) + + return db +} + +func getProd(id uint, products []Product) *Product { + for _, prod := range products { + if prod.ID == id { + return &prod + } + } + + return nil +} + +func createMyRender(base string) multitemplate.Renderer { + r := multitemplate.NewRenderer() + + f := template.FuncMap{ + "formatMoney": func(cents int) string { + return fmt.Sprintf("€%.2f", float64(float64(cents)/100)) + }, + "mult": func(x, y int) int { + return x * y + }, + "plus": func(a, b int) int { + return a + b + }, + "total": func(a Product, ac int, b Product, bc int, c Product, cc int) int { + return a.Price*ac + b.Price*bc + c.Price*cc + }, + "nowYear": func() string { + return time.Now().Format("2006") + }, + "getProd": getProd, + "countries": func() map[string]string { + return countries + }, + "menu": func() []MenuItem { + return getMenuItems() + }, + } + + r.AddFromFilesFuncs("404.html", f, path.Join(base, "base.html"), path.Join(base, "404.html")) + r.AddFromFilesFuncs("index", f, path.Join(base, "base.html"), path.Join(base, "index.html")) + r.AddFromFilesFuncs("orderInfo", f, path.Join(base, "base.html"), path.Join(base, "order_info.html")) + r.AddFromFilesFuncs("orderPending", f, path.Join(base, "base.html"), path.Join(base, "order_pending.html")) + r.AddFromFilesFuncs("orderThankyou", f, path.Join(base, "base.html"), path.Join(base, "order_thankyou.html")) + r.AddFromFilesFuncs("checkout", f, path.Join(base, "base.html"), path.Join(base, "order_checkout.html")) + + return r +} + +func main() { + if len(os.Args) > 1 { + ROOT_DIR = os.Args[1] + } + + go func() { + getMenuItems() + }() + + log.Printf("Running from with app root dir: %s\n", ROOT_DIR) + + configPath := path.Join(ROOT_DIR, "data/config/config.yaml") + configBytes, err := ioutil.ReadFile(configPath) + + if err != nil { + panic(fmt.Sprintf("Can't open config file at %s; %v", configPath, err)) + } + + if err := yaml.Unmarshal([]byte(configBytes), &config); err != nil { + panic(fmt.Sprintf("Can't parse config file at %s; %v", configPath, err)) + } + + if mollieClient, err = initMollie(); err != nil { + panic(err) + } + + db := GetDB() + + r := gin.Default() + r.HTMLRender = createMyRender(path.Join(ROOT_DIR, "templates")) + + r.Use(func(c *gin.Context) { + c.Set("db", db) + c.Next() + }) + + r.GET("/", index) + r.POST("/order", postGetOrderInfo) + r.GET("/order", index) + r.POST("/order/checkout", postCheckout) + r.POST("/order/create-order", createOrder) + r.POST("/order/webhook", postMollieWebhook) + r.GET("/order/thankyou", getPreOrderThankYou) + r.POST("/order/retry/:orderid", postOrderRetry) + r.GET("/order/pending/:orderid", getPendingOrder) + r.NoRoute(handle404) + + // sockPath := path.Join(ROOT_DIR, "run", SOCKNAME) + // sock := createSocket(sockPath) + + server := http.Server{ + Handler: r, + Addr: addr, + } + + fmt.Println("Running...") + go func() { + log.Fatal(server.ListenAndServe()) + }() + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + + // Block until a signal is received. + <-c + fmt.Println("Stopping...") + // os.Remove(path.Join(ROOT_DIR, "run", SOCKNAME)) +} diff --git a/menu.go b/menu.go new file mode 100644 index 0000000..41e0f62 --- /dev/null +++ b/menu.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "log" + "net/http" +) + +var menuURL = "http://www.thomaspol.com/wp-json/wp/v2/menu" + +type MenuItem struct { + Title string `json:"title"` + URL string `json:"url"` +} + +func _getMenuItems() func() []MenuItem { + var items []MenuItem + return func() []MenuItem { + if items == nil { + res, err := http.DefaultClient.Get(menuURL) + + if err != nil { + log.Printf("[Err] Error getting menu: %v", err) + return items + } + + dec := json.NewDecoder(res.Body) + tmpItems := []MenuItem{} + if err := dec.Decode(&tmpItems); err != nil { + return items + } + + items_ := []MenuItem{} + + for _, item := range tmpItems { + if item.URL == "#" { + continue + } + + items_ = append(items_, item) + } + + items = items_ + } + + return items + } +} + +var getMenuItems = _getMenuItems() diff --git a/mollie.go b/mollie.go new file mode 100644 index 0000000..3979738 --- /dev/null +++ b/mollie.go @@ -0,0 +1,39 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/VictorAvelar/mollie-api-go/v3/mollie" +) + +func createMolliePayment(preOrder PreOrder, shippingCost int) (*mollie.Response, *mollie.Payment, error) { + amount := preOrder.CalcTotal() + shippingCost + return mollieClient.Payments.Create(context.Background(), mollie.Payment{ + Amount: &mollie.Amount{ + Currency: "EUR", + Value: fmt.Sprintf("%.2f", float64(amount)/float64(100)), + }, + Description: fmt.Sprintf("Thomas Pol Shop"), + Metadata: map[string]interface{}{ + "preorderID": preOrder.ID, + }, + RedirectURL: fmt.Sprintf("%s/%v", config.MollieRedirectURL, preOrder.ID), + WebhookURL: config.MollieWebhook, + }, nil) +} + +func initMollie() (*mollie.Client, error) { + os.Setenv("MOLLIE_API_TOKEN", config.MollieToken) + apiTokenClient, err := mollie.NewClient(nil, mollie.NewConfig( + false, + mollie.APITokenEnv, + )) + + if err != nil { + return nil, err + } + + return apiTokenClient, nil +} diff --git a/nginx/alex-go.conf b/nginx/alex-go.conf new file mode 100644 index 0000000..9b4a565 --- /dev/null +++ b/nginx/alex-go.conf @@ -0,0 +1,37 @@ + server { + listen 80; + listen [::]:80; + server_name ; + client_max_body_size 20M; + + #charset koi8-r; + + + # access_log /usr/local/var/log/nginx/.access.log; + # error_log /usr/local/var/log/nginx/.error.log; + + + location /static { + alias /var/www/alex-go/dist; + gzip_static on; + expires max; + add_header Cache-Control public; + } + + location /favicon { + return 404 "Not Found"; + } + + location /robots.txt { + return 404 "Not Found"; + } + + location / { + proxy_pass http://unix://var/www/alex-go/run/flip.sock; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 5m; + } + } \ No newline at end of file diff --git a/nginx/template.conf b/nginx/template.conf new file mode 100644 index 0000000..6ee2c3e --- /dev/null +++ b/nginx/template.conf @@ -0,0 +1,37 @@ + server { + listen 80; + listen [::]:80; + server_name {{host_name}}; + client_max_body_size 20M; + + #charset koi8-r; + + + # access_log /usr/local/var/log/nginx/{{host_name}}.access.log; + # error_log /usr/local/var/log/nginx/{{host_name}}.error.log; + + + location /static { + alias {{root_dir}}/dist; + gzip_static on; + expires max; + add_header Cache-Control public; + } + + location /favicon { + return 404 "Not Found"; + } + + location /robots.txt { + return 404 "Not Found"; + } + + location / { + proxy_pass http://unix:/{{root_dir}}/run/flip.sock; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + client_max_body_size 5m; + } + } \ No newline at end of file diff --git a/order.go b/order.go new file mode 100644 index 0000000..5a4465b --- /dev/null +++ b/order.go @@ -0,0 +1,667 @@ +package main + +import ( + "bytes" + "context" + "fmt" + "html/template" + "log" + "net/http" + "path" + "regexp" + "strconv" + + "github.com/gin-gonic/gin" + "gopkg.in/gomail.v2" +) + +const SHIPPING = 675 +const SHIPPING_INT = 930 + +var countries = map[string]string{ + "AF": "Afghanistan", + "AX": "Åland Islands", + "AL": "Albania", + "DZ": "Algeria", + "AS": "American Samoa", + "AD": "AndorrA", + "AO": "Angola", + "AI": "Anguilla", + "AQ": "Antarctica", + "AG": "Antigua and Barbuda", + "AR": "Argentina", + "AM": "Armenia", + "AW": "Aruba", + "AU": "Australia", + "AT": "Austria", + "AZ": "Azerbaijan", + "BS": "Bahamas", + "BH": "Bahrain", + "BD": "Bangladesh", + "BB": "Barbados", + "BY": "Belarus", + "BE": "Belgium", + "BZ": "Belize", + "BJ": "Benin", + "BM": "Bermuda", + "BT": "Bhutan", + "BO": "Bolivia", + "BA": "Bosnia and Herzegovina", + "BW": "Botswana", + "BV": "Bouvet Island", + "BR": "Brazil", + "IO": "British Indian Ocean Territory", + "BN": "Brunei Darussalam", + "BG": "Bulgaria", + "BF": "Burkina Faso", + "BI": "Burundi", + "KH": "Cambodia", + "CM": "Cameroon", + "CA": "Canada", + "CV": "Cape Verde", + "KY": "Cayman Islands", + "CF": "Central African Republic", + "TD": "Chad", + "CL": "Chile", + "CN": "China", + "CX": "Christmas Island", + "CC": "Cocos (Keeling) Islands", + "CO": "Colombia", + "KM": "Comoros", + "CG": "Congo", + "CD": "Congo, The Democratic Republic of the", + "CK": "Cook Islands", + "CR": "Costa Rica", + "CI": "Cote D'Ivoire", + "HR": "Croatia", + "CU": "Cuba", + "CY": "Cyprus", + "CZ": "Czech Republic", + "DK": "Denmark", + "DJ": "Djibouti", + "DM": "Dominica", + "DO": "Dominican Republic", + "EC": "Ecuador", + "EG": "Egypt", + "SV": "El Salvador", + "GQ": "Equatorial Guinea", + "ER": "Eritrea", + "EE": "Estonia", + "ET": "Ethiopia", + "FK": "Falkland Islands (Malvinas", + "FO": "Faroe Islands", + "FJ": "Fiji", + "FI": "Finland", + "FR": "France", + "GF": "French Guiana", + "PF": "French Polynesia", + "TF": "French Southern Territories", + "GA": "Gabon", + "GM": "Gambia", + "GE": "Georgia", + "DE": "Germany", + "GH": "Ghana", + "GI": "Gibraltar", + "GR": "Greece", + "GL": "Greenland", + "GD": "Grenada", + "GP": "Guadeloupe", + "GU": "Guam", + "GT": "Guatemala", + "GG": "Guernsey", + "GN": "Guinea", + "GW": "Guinea-Bissau", + "GY": "Guyana", + "HT": "Haiti", + "HM": "Heard Island and Mcdonald Islands", + "VA": "Holy See (Vatican City State", + "HN": "Honduras", + "HK": "Hong Kong", + "HU": "Hungary", + "IS": "Iceland", + "IN": "India", + "ID": "Indonesia", + "IR": "Iran, Islamic Republic Of", + "IQ": "Iraq", + "IE": "Ireland", + "IM": "Isle of Man", + "IL": "Israel", + "IT": "Italy", + "JM": "Jamaica", + "JP": "Japan", + "JE": "Jersey", + "JO": "Jordan", + "KZ": "Kazakhstan", + "KE": "Kenya", + "KI": "Kiribati", + "KP": "Korea, Democratic People'S Republic of", + "KR": "Korea, Republic of", + "KW": "Kuwait", + "KG": "Kyrgyzstan", + "LA": "Lao People'S Democratic Republic", + "LV": "Latvia", + "LB": "Lebanon", + "LS": "Lesotho", + "LR": "Liberia", + "LY": "Libyan Arab Jamahiriya", + "LI": "Liechtenstein", + "LT": "Lithuania", + "LU": "Luxembourg", + "MO": "Macao", + "MK": "Macedonia, The Former Yugoslav Republic of", + "MG": "Madagascar", + "MW": "Malawi", + "MY": "Malaysia", + "MV": "Maldives", + "ML": "Mali", + "MT": "Malta", + "MH": "Marshall Islands", + "MQ": "Martinique", + "MR": "Mauritania", + "MU": "Mauritius", + "YT": "Mayotte", + "MX": "Mexico", + "FM": "Micronesia, Federated States of", + "MD": "Moldova, Republic of", + "MC": "Monaco", + "MN": "Mongolia", + "MS": "Montserrat", + "MA": "Morocco", + "MZ": "Mozambique", + "MM": "Myanmar", + "NA": "Namibia", + "NR": "Nauru", + "NP": "Nepal", + "NL": "Netherlands", + "AN": "Netherlands Antilles", + "NC": "New Caledonia", + "NZ": "New Zealand", + "NI": "Nicaragua", + "NE": "Niger", + "NG": "Nigeria", + "NU": "Niue", + "NF": "Norfolk Island", + "MP": "Northern Mariana Islands", + "NO": "Norway", + "OM": "Oman", + "PK": "Pakistan", + "PW": "Palau", + "PS": "Palestinian Territory, Occupied", + "PA": "Panama", + "PG": "Papua New Guinea", + "PY": "Paraguay", + "PE": "Peru", + "PH": "Philippines", + "PN": "Pitcairn", + "PL": "Poland", + "PT": "Portugal", + "PR": "Puerto Rico", + "QA": "Qatar", + "RE": "Reunion", + "RO": "Romania", + "RU": "Russian Federation", + "RW": "RWANDA", + "SH": "Saint Helena", + "KN": "Saint Kitts and Nevis", + "LC": "Saint Lucia", + "PM": "Saint Pierre and Miquelon", + "VC": "Saint Vincent and the Grenadines", + "WS": "Samoa", + "SM": "San Marino", + "ST": "Sao Tome and Principe", + "SA": "Saudi Arabia", + "SN": "Senegal", + "CS": "Serbia and Montenegro", + "SC": "Seychelles", + "SL": "Sierra Leone", + "SG": "Singapore", + "SK": "Slovakia", + "SI": "Slovenia", + "SB": "Solomon Islands", + "SO": "Somalia", + "ZA": "South Africa", + "GS": "South Georgia and the South Sandwich Islands", + "ES": "Spain", + "LK": "Sri Lanka", + "SD": "Sudan", + "SR": "Suriname", + "SJ": "Svalbard and Jan Mayen", + "SZ": "Swaziland", + "SE": "Sweden", + "CH": "Switzerland", + "SY": "Syrian Arab Republic", + "TW": "Taiwan, Province of China", + "TJ": "Tajikistan", + "TZ": "Tanzania, United Republic of", + "TH": "Thailand", + "TL": "Timor-Leste", + "TG": "Togo", + "TK": "Tokelau", + "TO": "Tonga", + "TT": "Trinidad and Tobago", + "TN": "Tunisia", + "TR": "Turkey", + "TM": "Turkmenistan", + "TC": "Turks and Caicos Islands", + "TV": "Tuvalu", + "UG": "Uganda", + "UA": "Ukraine", + "AE": "United Arab Emirates", + "GB": "United Kingdom", + "US": "United States", + "UM": "United States Minor Outlying Islands", + "UY": "Uruguay", + "UZ": "Uzbekistan", + "VU": "Vanuatu", + "VE": "Venezuela", + "VN": "Viet Nam", + "VG": "Virgin Islands, British", + "VI": "Virgin Islands, U.S", + "WF": "Wallis and Futuna", + "EH": "Western Sahara", + "YE": "Yemen", + "ZM": "Zambia", + "ZW": "Zimbabwe", +} + +type orderPayload struct { + Products []int `form:"product"` + Name string `form:"name"` + Streetname string `form:"streetname"` + Postcode string `form:"postcode"` + EmailAddress string `form:"email_address"` + City string `form:"city"` +} + +func sendMail(preOrder PreOrder, config Config) { + tpl, err := template.ParseFiles(path.Join(ROOT_DIR, "templates/preorder.email")) + + if err != nil { + panic(err) + } + m := gomail.NewMessage() + + var w bytes.Buffer + data := map[string]interface{}{ + "preOrder": preOrder, + } + + tpl.Execute(&w, data) + + m.SetHeader("From", config.FromAddr) + m.SetHeader("To", preOrder.Email) + m.SetAddressHeader("Bcc", config.BCC, "admin") + m.SetHeader("Subject", "Your Thomas Pol Shop order") + m.SetBody("text/html", w.String()) + + d := gomail.NewDialer(config.MailServer, config.MailPort, config.MailUser, config.MailPass) + + // Send the email to Bob, Cora and Dan. + if err := d.DialAndSend(m); err != nil { + panic(err) + } + + sendAdminMail(preOrder, config) +} + +func sendAdminMail(preOrder PreOrder, config Config) { + tpl, err := template.New("tpl").Funcs(template.FuncMap{ + "countries": func() map[string]string { + return countries + }, + }).ParseFiles(path.Join(ROOT_DIR, "templates/preorder_admin.email")) + + if err != nil { + panic(err) + } + + m := gomail.NewMessage() + + var w bytes.Buffer + data := map[string]interface{}{ + "preOrder": preOrder, + } + + tpl.Execute(&w, data) + + m.SetHeader("From", config.FromAddr) + m.SetHeader("To", config.BCC) + m.SetAddressHeader("Bcc", config.BCC, "admin") + m.SetHeader("Subject", "Thomas Pol order") + m.SetBody("text/html", w.String()) + + d := gomail.NewDialer(config.MailServer, config.MailPort, config.MailUser, config.MailPass) + + // Send the email to Bob, Cora and Dan. + if err := d.DialAndSend(m); err != nil { + panic(err) + } +} + +var prodRegexp = regexp.MustCompile(`products\[(\d+)\]`) + +func parseProducts(c *gin.Context) map[uint]int { + prods := map[uint]int{} + + c.Request.ParseForm() + for k, v := range c.Request.Form { + if m := prodRegexp.FindAllStringSubmatch(k, 1); len(m) > 0 { + + id, _ := strconv.ParseInt(m[0][1], 10, 64) + n, _ := strconv.ParseInt(v[0], 10, 64) + prods[uint(id)] = int(n) + } + } + + return prods +} + +type Shipping struct { + Name string + Email string + Address string + Postcode string + City string + Country string +} + +func (s Shipping) Valid() bool { + if s.Name == "" { + return false + } + if s.Email == "" { + return false + } + if s.Address == "" { + return false + } + if s.Postcode == "" { + return false + } + if s.City == "" { + return false + } + + if s.Country == "" { + return false + } + + return true +} + +func parseShipping(c *gin.Context) Shipping { + shipping := Shipping{} + + c.Request.ParseForm() + for k, v := range c.Request.Form { + switch k { + case "name": + shipping.Name = v[0] + case "email": + shipping.Email = v[0] + case "address": + shipping.Address = v[0] + case "postcode": + shipping.Postcode = v[0] + case "city": + shipping.City = v[0] + case "country": + shipping.Country = v[0] + } + } + + if shipping.Country == "" { + shipping.Country = "NL" + } + + return shipping +} + +func postGetOrderInfo(c *gin.Context) { + db := getDB(c) + products := []Product{} + db.Find(&products) + c.Request.ParseForm() + prods := parseProducts(c) + shipping := parseShipping(c) + total := 0 + + for p, q := range prods { + cur := getProd(p, products) + + if cur == nil { + continue + } + + total += q * cur.Price + } + + c.HTML(http.StatusOK, "checkout", map[string]interface{}{ + "error": "", + "total": total, + "products": products, + "shipping": shipping, + "order": prods, + }) +} + +func postCheckout(c *gin.Context) { + db := getDB(c) + products := []Product{} + db.Find(&products) + c.Request.ParseForm() + prods := parseProducts(c) + + total := 0 + + for p, q := range prods { + cur := getProd(p, products) + + if cur == nil { + continue + } + + total += q * cur.Price + } + + shipping := parseShipping(c) + + if !shipping.Valid() { + c.HTML(http.StatusOK, "checkout", map[string]interface{}{ + "error": "All fields are required", + "total": total, + "products": products, + "shipping": shipping, + "order": prods, + }) + return + } + + shippingCost := SHIPPING + shippingLabel := "Shipping NL" + + if shipping.Country != "NL" { + shippingCost = SHIPPING_INT + shippingLabel = "Shipping international" + } + + total += shippingCost + + c.HTML(http.StatusOK, "orderInfo", map[string]interface{}{ + "total": total, + "products": products, + "shipping": shipping, + "shippingCost": shippingCost, + "shippingLabel": shippingLabel, + "order": prods, + }) + +} + +func createOrder(c *gin.Context) { + db := getDB(c) + products := []Product{} + db.Find(&products) + c.Request.ParseForm() + prods := parseProducts(c) + + shipping := parseShipping(c) + + preOrder := PreOrder{ + Name: shipping.Name, + Email: shipping.Email, + Address: shipping.Address, + Postcode: shipping.Postcode, + City: shipping.City, + Country: shipping.Country, + Status: PRE_ORDER_STATE_CREATED, + } + + db.Create(&preOrder) + + for p, q := range prods { + for i := 0; i < q; i++ { + db.Create(&Item{ + ProductID: p, + PreOrderID: preOrder.ID, + }) + } + } + + shippingCost := SHIPPING + if shipping.Country != "NL" { + shippingCost = SHIPPING_INT + } + + db.Preload("Items").Preload("Items.Product").Where("id = ?", preOrder.ID).Find(&preOrder) + + _, payment, err := createMolliePayment(preOrder, shippingCost) + + if err != nil { + log.Printf("Something went wrong creating payment: %v", err) + c.AbortWithError(500, fmt.Errorf("I'am sorry, something went wrong...:(")) + return + } + + molliePayment := MolliePayment{ + MolliePaymentID: payment.ID, + Amount: preOrder.CalcTotal() + shippingCost, + Status: payment.Status, + PreOrderID: preOrder.ID, + } + + db.Create(&molliePayment) + + c.Redirect(http.StatusFound, payment.Links.Checkout.Href) +} + +func postMollieWebhook(c *gin.Context) { + db := getDB(c) + + paymentID := c.Request.FormValue("id") + + _, payment, err := mollieClient.Payments.Get(context.Background(), paymentID, nil) + + if err != nil { + log.Printf("Error get payment from mollie; %v; %s", err, paymentID) + c.AbortWithError(500, fmt.Errorf("Deze bestelling is onbekend")) + return + } + + molliePayment := &MolliePayment{} + + if err := db.Preload("PreOrder").Where("mollie_payment_id = ?", paymentID).Find(&molliePayment).Error; err != nil { + log.Printf("Error get payment from db; %v; %s", err, paymentID) + c.AbortWithError(500, fmt.Errorf("Unknown order")) + return + } + + if payment.Status != molliePayment.Status { + molliePayment.Status = payment.Status + db.Save(&molliePayment) + + preOrder := PreOrder{} + + db.Preload("Items").Preload("Items.Product").Where("id = ?", molliePayment.PreOrderID).Find(&preOrder) + + if molliePayment.Status == "paid" { + sendMail(preOrder, config) + } + } + + c.Status(200) +} + +func postOrderRetry(c *gin.Context) { + orderID := c.Param("orderid") + + db := getDB(c) + + preOrder := &PreOrder{} + + if err := db.Preload("Items").Preload("Items.Product").Where("id = ?", orderID).Find(&preOrder).Error; err != nil { + c.AbortWithError(500, fmt.Errorf("This order is unknown")) + return + } + + if preOrder.ID.String() == nullUUID.String() { + c.AbortWithError(500, fmt.Errorf("Unknown Order")) + return + } + + db.Find(&preOrder) + + shippingCost := SHIPPING + if preOrder.Country != "NL" { + shippingCost = SHIPPING_INT + } + + _, payment, err := createMolliePayment(*preOrder, shippingCost) + + if err != nil { + c.AbortWithError(500, fmt.Errorf("Sorry, something went wrong...:(")) + return + } + + molliePayment := MolliePayment{ + MolliePaymentID: payment.ID, + Amount: preOrder.CalcTotal() + SHIPPING, + Status: payment.Status, + PreOrderID: preOrder.ID, + } + + db.Create(&molliePayment) + + c.Redirect(http.StatusFound, payment.Links.Checkout.Href) +} + +func getPendingOrder(c *gin.Context) { + orderID := c.Param("orderid") + + db := getDB(c) + + payments := []*MolliePayment{} + + if err := db.Where("pre_order_id = ?", orderID).Order("created_at desc").Find(&payments).Error; err != nil { + c.AbortWithError(500, fmt.Errorf("Unknown Order")) + return + } + + if len(payments) == 0 { + c.AbortWithError(500, fmt.Errorf("Unknown Order")) + return + } + + payment := payments[0] + + if payment.Status == "paid" { + c.Redirect(http.StatusFound, "/order/thankyou") + return + } + + c.HTML(http.StatusOK, "orderPending", map[string]interface{}{"payment": payment, "orderID": orderID}) +} + +func getPreOrderThankYou(c *gin.Context) { + c.HTML(http.StatusOK, "orderThankyou", nil) +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1e57009 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "cohen_site", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "babel-core": "^6.26.0", + "babel-loader": "^7.1.4", + "babel-preset-es2015": "^6.24.1", + "gulp": "^4.0.2", + "gulp-autoprefixer": "^6.1.0", + "gulp-clean-css": "^4.2.0", + "gulp-newer": "^1.4.0", + "gulp-sass": "^5.1.0", + "webpack": "^4.1.1", + "webpack-stream": "^4.0.2" + }, + "dependencies": { + "sass": "^1.50.1", + "uglifyjs-webpack-plugin": "^2.2.0" + } +} diff --git a/preorder_test.go b/preorder_test.go new file mode 100644 index 0000000..99be7c8 --- /dev/null +++ b/preorder_test.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "io/ioutil" + "path" + "testing" + + yaml "gopkg.in/yaml.v2" +) + +func TestSendMail(t *testing.T) { + db := GetDB() + config := Config{} + configPath := path.Join(ROOT_DIR, "data/config/config.yaml") + configBytes, err := ioutil.ReadFile(configPath) + + if err != nil { + panic(fmt.Sprintf("Can't open config file at %s; %v", configPath, err)) + } + + if err := yaml.Unmarshal([]byte(configBytes), &config); err != nil { + panic(fmt.Sprintf("Can't parse config file at %s; %v", configPath, err)) + } + + preOrder := PreOrder{} + + db.Preload("Items").Preload("Items.Product").Where("id = ?", "66297049-6019-45a3-bb98-959d4c2476d9").Find(&preOrder) + sendMail(preOrder, config) +} diff --git a/run/.keep b/run/.keep new file mode 100644 index 0000000..e69de29 diff --git a/seed.sql b/seed.sql new file mode 100644 index 0000000..f07e1d1 --- /dev/null +++ b/seed.sql @@ -0,0 +1,3 @@ +INSERT INTO "products" VALUES(1,'2021-12-11 09:53:59.584728+01:00','2021-12-11 09:53:59.584728+01:00',NULL,'In America (CD)','/static/img/tpia_front.png','In America (CD)', 1000); +INSERT INTO "products" VALUES(2,'2021-12-11 09:53:59.584728+01:00','2021-12-11 09:53:59.584728+01:00',NULL,'In America (CD) + Blue Soil (LP)','/static/img/combi.png','In America (CD) + Blue Soil (LP)', 3000); +INSERT INTO "products" VALUES(3,'2021-12-11 09:53:59.584728+01:00','2021-12-11 09:53:59.584728+01:00',NULL,'Blue Soil (LP)','/static/img/blue_soil.jpg','Blue Soil (LP)', 2500); \ No newline at end of file diff --git a/src/fonts/socicon.woff b/src/fonts/socicon.woff new file mode 100644 index 0000000..0aa5569 Binary files /dev/null and b/src/fonts/socicon.woff differ diff --git a/src/img/blue_soil.jpg b/src/img/blue_soil.jpg new file mode 100644 index 0000000..c6deb74 Binary files /dev/null and b/src/img/blue_soil.jpg differ diff --git a/src/img/caret.png b/src/img/caret.png new file mode 100644 index 0000000..87ce44f Binary files /dev/null and b/src/img/caret.png differ diff --git a/src/img/combi.jpg b/src/img/combi.jpg new file mode 100644 index 0000000..4469382 Binary files /dev/null and b/src/img/combi.jpg differ diff --git a/src/img/favicon.ico b/src/img/favicon.ico new file mode 100644 index 0000000..330e0f1 Binary files /dev/null and b/src/img/favicon.ico differ diff --git a/src/img/favicon.jpg b/src/img/favicon.jpg new file mode 100644 index 0000000..89e52db Binary files /dev/null and b/src/img/favicon.jpg differ diff --git a/src/img/tpia_front.png b/src/img/tpia_front.png new file mode 100644 index 0000000..ac36cef Binary files /dev/null and b/src/img/tpia_front.png differ diff --git a/src/js/shared.js b/src/js/shared.js new file mode 100644 index 0000000..aff940c --- /dev/null +++ b/src/js/shared.js @@ -0,0 +1,21 @@ +!function () { + var t = document.querySelector('.js-mobile-trigger') + var menu = document.querySelector('.js-menu') + var close = document.querySelector('.js-close') + function foo() { + menu.classList.remove('active') + window.removeEventListener('click', foo) + } + t.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + menu.classList.add('active') + window.addEventListener('click', foo) + }) + + close.addEventListener('click', function (e) { + e.preventDefault() + e.stopPropagation() + foo() + }) +}() \ No newline at end of file diff --git a/src/sass/_color.scss b/src/sass/_color.scss new file mode 100644 index 0000000..d11ad05 --- /dev/null +++ b/src/sass/_color.scss @@ -0,0 +1,3 @@ +$black: #111; +$primary:#00f596; +$grey: #BFB7B0; \ No newline at end of file diff --git a/src/sass/_hamburger.scss b/src/sass/_hamburger.scss new file mode 100644 index 0000000..e1bb63b --- /dev/null +++ b/src/sass/_hamburger.scss @@ -0,0 +1,7 @@ +/*! + * Hamburgers + * @description Tasty CSS-animated hamburgers + * @author Jonathan Suh @jonsuh + * @site https://jonsuh.com/hamburgers + * @link https://github.com/jonsuh/hamburgers + */.hamburger{font:inherit;display:inline-block;overflow:visible;margin:0;padding:15px;cursor:pointer;transition-timing-function:linear;transition-duration:.15s;transition-property:opacity,filter;text-transform:none;color:inherit;border:0;background-color:transparent}.hamburger.is-active:hover,.hamburger:hover{opacity:.7}.hamburger.is-active .hamburger-inner,.hamburger.is-active .hamburger-inner:after,.hamburger.is-active .hamburger-inner:before{background-color:#000}.hamburger-box{position:relative;display:inline-block;width:40px;height:24px}.hamburger-inner{top:50%;display:block;margin-top:-2px}.hamburger-inner,.hamburger-inner:after,.hamburger-inner:before{position:absolute;width:40px;height:4px;transition-timing-function:ease;transition-duration:.15s;transition-property:transform;border-radius:4px;background-color:#000}.hamburger-inner:after,.hamburger-inner:before{display:block;content:""}.hamburger-inner:before{top:-10px}.hamburger-inner:after{bottom:-10px}.hamburger--3dx .hamburger-box{perspective:80px}.hamburger--3dx .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dx .hamburger-inner:after,.hamburger--3dx .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dx.is-active .hamburger-inner{transform:rotateY(180deg);background-color:transparent!important}.hamburger--3dx.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dx.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--3dx-r .hamburger-box{perspective:80px}.hamburger--3dx-r .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dx-r .hamburger-inner:after,.hamburger--3dx-r .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dx-r.is-active .hamburger-inner{transform:rotateY(-180deg);background-color:transparent!important}.hamburger--3dx-r.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dx-r.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--3dy .hamburger-box{perspective:80px}.hamburger--3dy .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dy .hamburger-inner:after,.hamburger--3dy .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dy.is-active .hamburger-inner{transform:rotateX(-180deg);background-color:transparent!important}.hamburger--3dy.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dy.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--3dy-r .hamburger-box{perspective:80px}.hamburger--3dy-r .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dy-r .hamburger-inner:after,.hamburger--3dy-r .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dy-r.is-active .hamburger-inner{transform:rotateX(180deg);background-color:transparent!important}.hamburger--3dy-r.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dy-r.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--3dxy .hamburger-box{perspective:80px}.hamburger--3dxy .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dxy .hamburger-inner:after,.hamburger--3dxy .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dxy.is-active .hamburger-inner{transform:rotateX(180deg) rotateY(180deg);background-color:transparent!important}.hamburger--3dxy.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dxy.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--3dxy-r .hamburger-box{perspective:80px}.hamburger--3dxy-r .hamburger-inner{transition:transform .15s cubic-bezier(.645,.045,.355,1),background-color 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dxy-r .hamburger-inner:after,.hamburger--3dxy-r .hamburger-inner:before{transition:transform 0s cubic-bezier(.645,.045,.355,1) .1s}.hamburger--3dxy-r.is-active .hamburger-inner{transform:rotateX(180deg) rotateY(180deg) rotate(-180deg);background-color:transparent!important}.hamburger--3dxy-r.is-active .hamburger-inner:before{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--3dxy-r.is-active .hamburger-inner:after{transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--arrow.is-active .hamburger-inner:before{transform:translate3d(-8px,0,0) rotate(-45deg) scaleX(.7)}.hamburger--arrow.is-active .hamburger-inner:after{transform:translate3d(-8px,0,0) rotate(45deg) scaleX(.7)}.hamburger--arrow-r.is-active .hamburger-inner:before{transform:translate3d(8px,0,0) rotate(45deg) scaleX(.7)}.hamburger--arrow-r.is-active .hamburger-inner:after{transform:translate3d(8px,0,0) rotate(-45deg) scaleX(.7)}.hamburger--arrowalt .hamburger-inner:before{transition:top .1s ease .1s,transform .1s cubic-bezier(.165,.84,.44,1)}.hamburger--arrowalt .hamburger-inner:after{transition:bottom .1s ease .1s,transform .1s cubic-bezier(.165,.84,.44,1)}.hamburger--arrowalt.is-active .hamburger-inner:before{top:0;transition:top .1s ease,transform .1s cubic-bezier(.895,.03,.685,.22) .1s;transform:translate3d(-8px,-10px,0) rotate(-45deg) scaleX(.7)}.hamburger--arrowalt.is-active .hamburger-inner:after{bottom:0;transition:bottom .1s ease,transform .1s cubic-bezier(.895,.03,.685,.22) .1s;transform:translate3d(-8px,10px,0) rotate(45deg) scaleX(.7)}.hamburger--arrowalt-r .hamburger-inner:before{transition:top .1s ease .1s,transform .1s cubic-bezier(.165,.84,.44,1)}.hamburger--arrowalt-r .hamburger-inner:after{transition:bottom .1s ease .1s,transform .1s cubic-bezier(.165,.84,.44,1)}.hamburger--arrowalt-r.is-active .hamburger-inner:before{top:0;transition:top .1s ease,transform .1s cubic-bezier(.895,.03,.685,.22) .1s;transform:translate3d(8px,-10px,0) rotate(45deg) scaleX(.7)}.hamburger--arrowalt-r.is-active .hamburger-inner:after{bottom:0;transition:bottom .1s ease,transform .1s cubic-bezier(.895,.03,.685,.22) .1s;transform:translate3d(8px,10px,0) rotate(-45deg) scaleX(.7)}.hamburger--arrowturn.is-active .hamburger-inner{transform:rotate(-180deg)}.hamburger--arrowturn.is-active .hamburger-inner:before{transform:translate3d(8px,0,0) rotate(45deg) scaleX(.7)}.hamburger--arrowturn.is-active .hamburger-inner:after{transform:translate3d(8px,0,0) rotate(-45deg) scaleX(.7)}.hamburger--arrowturn-r.is-active .hamburger-inner{transform:rotate(-180deg)}.hamburger--arrowturn-r.is-active .hamburger-inner:before{transform:translate3d(-8px,0,0) rotate(-45deg) scaleX(.7)}.hamburger--arrowturn-r.is-active .hamburger-inner:after{transform:translate3d(-8px,0,0) rotate(45deg) scaleX(.7)}.hamburger--boring .hamburger-inner,.hamburger--boring .hamburger-inner:after,.hamburger--boring .hamburger-inner:before{transition-property:none}.hamburger--boring.is-active .hamburger-inner{transform:rotate(45deg)}.hamburger--boring.is-active .hamburger-inner:before{top:0;opacity:0}.hamburger--boring.is-active .hamburger-inner:after{bottom:0;transform:rotate(-90deg)}.hamburger--collapse .hamburger-inner{top:auto;bottom:0;transition-delay:.13s;transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:.13s}.hamburger--collapse .hamburger-inner:after{top:-20px;transition:top .2s cubic-bezier(.33333,.66667,.66667,1) .2s,opacity .1s linear}.hamburger--collapse .hamburger-inner:before{transition:top .12s cubic-bezier(.33333,.66667,.66667,1) .2s,transform .13s cubic-bezier(.55,.055,.675,.19)}.hamburger--collapse.is-active .hamburger-inner{transition-delay:.22s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--collapse.is-active .hamburger-inner:after{top:0;transition:top .2s cubic-bezier(.33333,0,.66667,.33333),opacity .1s linear .22s;opacity:0}.hamburger--collapse.is-active .hamburger-inner:before{top:0;transition:top .1s cubic-bezier(.33333,0,.66667,.33333) .16s,transform .13s cubic-bezier(.215,.61,.355,1) .25s;transform:rotate(-90deg)}.hamburger--collapse-r .hamburger-inner{top:auto;bottom:0;transition-delay:.13s;transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:.13s}.hamburger--collapse-r .hamburger-inner:after{top:-20px;transition:top .2s cubic-bezier(.33333,.66667,.66667,1) .2s,opacity .1s linear}.hamburger--collapse-r .hamburger-inner:before{transition:top .12s cubic-bezier(.33333,.66667,.66667,1) .2s,transform .13s cubic-bezier(.55,.055,.675,.19)}.hamburger--collapse-r.is-active .hamburger-inner{transition-delay:.22s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:translate3d(0,-10px,0) rotate(45deg)}.hamburger--collapse-r.is-active .hamburger-inner:after{top:0;transition:top .2s cubic-bezier(.33333,0,.66667,.33333),opacity .1s linear .22s;opacity:0}.hamburger--collapse-r.is-active .hamburger-inner:before{top:0;transition:top .1s cubic-bezier(.33333,0,.66667,.33333) .16s,transform .13s cubic-bezier(.215,.61,.355,1) .25s;transform:rotate(90deg)}.hamburger--elastic .hamburger-inner{top:2px;transition-timing-function:cubic-bezier(.68,-.55,.265,1.55);transition-duration:.275s}.hamburger--elastic .hamburger-inner:before{top:10px;transition:opacity .125s ease .275s}.hamburger--elastic .hamburger-inner:after{top:20px;transition:transform .275s cubic-bezier(.68,-.55,.265,1.55)}.hamburger--elastic.is-active .hamburger-inner{transition-delay:75ms;transform:translate3d(0,10px,0) rotate(135deg)}.hamburger--elastic.is-active .hamburger-inner:before{transition-delay:0s;opacity:0}.hamburger--elastic.is-active .hamburger-inner:after{transition-delay:75ms;transform:translate3d(0,-20px,0) rotate(-270deg)}.hamburger--elastic-r .hamburger-inner{top:2px;transition-timing-function:cubic-bezier(.68,-.55,.265,1.55);transition-duration:.275s}.hamburger--elastic-r .hamburger-inner:before{top:10px;transition:opacity .125s ease .275s}.hamburger--elastic-r .hamburger-inner:after{top:20px;transition:transform .275s cubic-bezier(.68,-.55,.265,1.55)}.hamburger--elastic-r.is-active .hamburger-inner{transition-delay:75ms;transform:translate3d(0,10px,0) rotate(-135deg)}.hamburger--elastic-r.is-active .hamburger-inner:before{transition-delay:0s;opacity:0}.hamburger--elastic-r.is-active .hamburger-inner:after{transition-delay:75ms;transform:translate3d(0,-20px,0) rotate(270deg)}.hamburger--emphatic{overflow:hidden}.hamburger--emphatic .hamburger-inner{transition:background-color .125s ease-in .175s}.hamburger--emphatic .hamburger-inner:before{left:0;transition:transform .125s cubic-bezier(.6,.04,.98,.335),top .05s linear .125s,left .125s ease-in .175s}.hamburger--emphatic .hamburger-inner:after{top:10px;right:0;transition:transform .125s cubic-bezier(.6,.04,.98,.335),top .05s linear .125s,right .125s ease-in .175s}.hamburger--emphatic.is-active .hamburger-inner{transition-delay:0s;transition-timing-function:ease-out;background-color:transparent!important}.hamburger--emphatic.is-active .hamburger-inner:before{top:-80px;left:-80px;transition:left .125s ease-out,top .05s linear .125s,transform .125s cubic-bezier(.075,.82,.165,1) .175s;transform:translate3d(80px,80px,0) rotate(45deg)}.hamburger--emphatic.is-active .hamburger-inner:after{top:-80px;right:-80px;transition:right .125s ease-out,top .05s linear .125s,transform .125s cubic-bezier(.075,.82,.165,1) .175s;transform:translate3d(-80px,80px,0) rotate(-45deg)}.hamburger--emphatic-r{overflow:hidden}.hamburger--emphatic-r .hamburger-inner{transition:background-color .125s ease-in .175s}.hamburger--emphatic-r .hamburger-inner:before{left:0;transition:transform .125s cubic-bezier(.6,.04,.98,.335),top .05s linear .125s,left .125s ease-in .175s}.hamburger--emphatic-r .hamburger-inner:after{top:10px;right:0;transition:transform .125s cubic-bezier(.6,.04,.98,.335),top .05s linear .125s,right .125s ease-in .175s}.hamburger--emphatic-r.is-active .hamburger-inner{transition-delay:0s;transition-timing-function:ease-out;background-color:transparent!important}.hamburger--emphatic-r.is-active .hamburger-inner:before{top:80px;left:-80px;transition:left .125s ease-out,top .05s linear .125s,transform .125s cubic-bezier(.075,.82,.165,1) .175s;transform:translate3d(80px,-80px,0) rotate(-45deg)}.hamburger--emphatic-r.is-active .hamburger-inner:after{top:80px;right:-80px;transition:right .125s ease-out,top .05s linear .125s,transform .125s cubic-bezier(.075,.82,.165,1) .175s;transform:translate3d(-80px,-80px,0) rotate(45deg)}.hamburger--minus .hamburger-inner:after,.hamburger--minus .hamburger-inner:before{transition:bottom .08s ease-out 0s,top .08s ease-out 0s,opacity 0s linear}.hamburger--minus.is-active .hamburger-inner:after,.hamburger--minus.is-active .hamburger-inner:before{transition:bottom .08s ease-out,top .08s ease-out,opacity 0s linear .08s;opacity:0}.hamburger--minus.is-active .hamburger-inner:before{top:0}.hamburger--minus.is-active .hamburger-inner:after{bottom:0}.hamburger--slider .hamburger-inner{top:2px}.hamburger--slider .hamburger-inner:before{top:10px;transition-timing-function:ease;transition-duration:.15s;transition-property:transform,opacity}.hamburger--slider .hamburger-inner:after{top:20px}.hamburger--slider.is-active .hamburger-inner{transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--slider.is-active .hamburger-inner:before{transform:rotate(-45deg) translate3d(-5.71429px,-6px,0);opacity:0}.hamburger--slider.is-active .hamburger-inner:after{transform:translate3d(0,-20px,0) rotate(-90deg)}.hamburger--slider-r .hamburger-inner{top:2px}.hamburger--slider-r .hamburger-inner:before{top:10px;transition-timing-function:ease;transition-duration:.15s;transition-property:transform,opacity}.hamburger--slider-r .hamburger-inner:after{top:20px}.hamburger--slider-r.is-active .hamburger-inner{transform:translate3d(0,10px,0) rotate(-45deg)}.hamburger--slider-r.is-active .hamburger-inner:before{transform:rotate(45deg) translate3d(5.71429px,-6px,0);opacity:0}.hamburger--slider-r.is-active .hamburger-inner:after{transform:translate3d(0,-20px,0) rotate(90deg)}.hamburger--spin .hamburger-inner{transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:.22s}.hamburger--spin .hamburger-inner:before{transition:top .1s ease-in .25s,opacity .1s ease-in}.hamburger--spin .hamburger-inner:after{transition:bottom .1s ease-in .25s,transform .22s cubic-bezier(.55,.055,.675,.19)}.hamburger--spin.is-active .hamburger-inner{transition-delay:.12s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:rotate(225deg)}.hamburger--spin.is-active .hamburger-inner:before{top:0;transition:top .1s ease-out,opacity .1s ease-out .12s;opacity:0}.hamburger--spin.is-active .hamburger-inner:after{bottom:0;transition:bottom .1s ease-out,transform .22s cubic-bezier(.215,.61,.355,1) .12s;transform:rotate(-90deg)}.hamburger--spin-r .hamburger-inner{transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:.22s}.hamburger--spin-r .hamburger-inner:before{transition:top .1s ease-in .25s,opacity .1s ease-in}.hamburger--spin-r .hamburger-inner:after{transition:bottom .1s ease-in .25s,transform .22s cubic-bezier(.55,.055,.675,.19)}.hamburger--spin-r.is-active .hamburger-inner{transition-delay:.12s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:rotate(-225deg)}.hamburger--spin-r.is-active .hamburger-inner:before{top:0;transition:top .1s ease-out,opacity .1s ease-out .12s;opacity:0}.hamburger--spin-r.is-active .hamburger-inner:after{bottom:0;transition:bottom .1s ease-out,transform .22s cubic-bezier(.215,.61,.355,1) .12s;transform:rotate(90deg)}.hamburger--spring .hamburger-inner{top:2px;transition:background-color 0s linear .13s}.hamburger--spring .hamburger-inner:before{top:10px;transition:top .1s cubic-bezier(.33333,.66667,.66667,1) .2s,transform .13s cubic-bezier(.55,.055,.675,.19)}.hamburger--spring .hamburger-inner:after{top:20px;transition:top .2s cubic-bezier(.33333,.66667,.66667,1) .2s,transform .13s cubic-bezier(.55,.055,.675,.19)}.hamburger--spring.is-active .hamburger-inner{transition-delay:.22s;background-color:transparent!important}.hamburger--spring.is-active .hamburger-inner:before{top:0;transition:top .1s cubic-bezier(.33333,0,.66667,.33333) .15s,transform .13s cubic-bezier(.215,.61,.355,1) .22s;transform:translate3d(0,10px,0) rotate(45deg)}.hamburger--spring.is-active .hamburger-inner:after{top:0;transition:top .2s cubic-bezier(.33333,0,.66667,.33333),transform .13s cubic-bezier(.215,.61,.355,1) .22s;transform:translate3d(0,10px,0) rotate(-45deg)}.hamburger--spring-r .hamburger-inner{top:auto;bottom:0;transition-delay:0s;transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:.13s}.hamburger--spring-r .hamburger-inner:after{top:-20px;transition:top .2s cubic-bezier(.33333,.66667,.66667,1) .2s,opacity 0s linear}.hamburger--spring-r .hamburger-inner:before{transition:top .1s cubic-bezier(.33333,.66667,.66667,1) .2s,transform .13s cubic-bezier(.55,.055,.675,.19)}.hamburger--spring-r.is-active .hamburger-inner{transition-delay:.22s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:translate3d(0,-10px,0) rotate(-45deg)}.hamburger--spring-r.is-active .hamburger-inner:after{top:0;transition:top .2s cubic-bezier(.33333,0,.66667,.33333),opacity 0s linear .22s;opacity:0}.hamburger--spring-r.is-active .hamburger-inner:before{top:0;transition:top .1s cubic-bezier(.33333,0,.66667,.33333) .15s,transform .13s cubic-bezier(.215,.61,.355,1) .22s;transform:rotate(90deg)}.hamburger--stand .hamburger-inner{transition:transform 75ms cubic-bezier(.55,.055,.675,.19) .15s,background-color 0s linear 75ms}.hamburger--stand .hamburger-inner:before{transition:top 75ms ease-in 75ms,transform 75ms cubic-bezier(.55,.055,.675,.19) 0s}.hamburger--stand .hamburger-inner:after{transition:bottom 75ms ease-in 75ms,transform 75ms cubic-bezier(.55,.055,.675,.19) 0s}.hamburger--stand.is-active .hamburger-inner{transition:transform 75ms cubic-bezier(.215,.61,.355,1) 0s,background-color 0s linear .15s;transform:rotate(90deg);background-color:transparent!important}.hamburger--stand.is-active .hamburger-inner:before{top:0;transition:top 75ms ease-out .1s,transform 75ms cubic-bezier(.215,.61,.355,1) .15s;transform:rotate(-45deg)}.hamburger--stand.is-active .hamburger-inner:after{bottom:0;transition:bottom 75ms ease-out .1s,transform 75ms cubic-bezier(.215,.61,.355,1) .15s;transform:rotate(45deg)}.hamburger--stand-r .hamburger-inner{transition:transform 75ms cubic-bezier(.55,.055,.675,.19) .15s,background-color 0s linear 75ms}.hamburger--stand-r .hamburger-inner:before{transition:top 75ms ease-in 75ms,transform 75ms cubic-bezier(.55,.055,.675,.19) 0s}.hamburger--stand-r .hamburger-inner:after{transition:bottom 75ms ease-in 75ms,transform 75ms cubic-bezier(.55,.055,.675,.19) 0s}.hamburger--stand-r.is-active .hamburger-inner{transition:transform 75ms cubic-bezier(.215,.61,.355,1) 0s,background-color 0s linear .15s;transform:rotate(-90deg);background-color:transparent!important}.hamburger--stand-r.is-active .hamburger-inner:before{top:0;transition:top 75ms ease-out .1s,transform 75ms cubic-bezier(.215,.61,.355,1) .15s;transform:rotate(-45deg)}.hamburger--stand-r.is-active .hamburger-inner:after{bottom:0;transition:bottom 75ms ease-out .1s,transform 75ms cubic-bezier(.215,.61,.355,1) .15s;transform:rotate(45deg)}.hamburger--squeeze .hamburger-inner{transition-timing-function:cubic-bezier(.55,.055,.675,.19);transition-duration:75ms}.hamburger--squeeze .hamburger-inner:before{transition:top 75ms ease .12s,opacity 75ms ease}.hamburger--squeeze .hamburger-inner:after{transition:bottom 75ms ease .12s,transform 75ms cubic-bezier(.55,.055,.675,.19)}.hamburger--squeeze.is-active .hamburger-inner{transition-delay:.12s;transition-timing-function:cubic-bezier(.215,.61,.355,1);transform:rotate(45deg)}.hamburger--squeeze.is-active .hamburger-inner:before{top:0;transition:top 75ms ease,opacity 75ms ease .12s;opacity:0}.hamburger--squeeze.is-active .hamburger-inner:after{bottom:0;transition:bottom 75ms ease,transform 75ms cubic-bezier(.215,.61,.355,1) .12s;transform:rotate(-90deg)}.hamburger--vortex .hamburger-inner{transition-timing-function:cubic-bezier(.19,1,.22,1);transition-duration:.2s}.hamburger--vortex .hamburger-inner:after,.hamburger--vortex .hamburger-inner:before{transition-delay:.1s;transition-timing-function:linear;transition-duration:0s}.hamburger--vortex .hamburger-inner:before{transition-property:top,opacity}.hamburger--vortex .hamburger-inner:after{transition-property:bottom,transform}.hamburger--vortex.is-active .hamburger-inner{transition-timing-function:cubic-bezier(.19,1,.22,1);transform:rotate(765deg)}.hamburger--vortex.is-active .hamburger-inner:after,.hamburger--vortex.is-active .hamburger-inner:before{transition-delay:0s}.hamburger--vortex.is-active .hamburger-inner:before{top:0;opacity:0}.hamburger--vortex.is-active .hamburger-inner:after{bottom:0;transform:rotate(90deg)}.hamburger--vortex-r .hamburger-inner{transition-timing-function:cubic-bezier(.19,1,.22,1);transition-duration:.2s}.hamburger--vortex-r .hamburger-inner:after,.hamburger--vortex-r .hamburger-inner:before{transition-delay:.1s;transition-timing-function:linear;transition-duration:0s}.hamburger--vortex-r .hamburger-inner:before{transition-property:top,opacity}.hamburger--vortex-r .hamburger-inner:after{transition-property:bottom,transform}.hamburger--vortex-r.is-active .hamburger-inner{transition-timing-function:cubic-bezier(.19,1,.22,1);transform:rotate(-765deg)}.hamburger--vortex-r.is-active .hamburger-inner:after,.hamburger--vortex-r.is-active .hamburger-inner:before{transition-delay:0s}.hamburger--vortex-r.is-active .hamburger-inner:before{top:0;opacity:0}.hamburger--vortex-r.is-active .hamburger-inner:after{bottom:0;transform:rotate(-90deg)} \ No newline at end of file diff --git a/src/sass/_menu.scss b/src/sass/_menu.scss new file mode 100644 index 0000000..59404eb --- /dev/null +++ b/src/sass/_menu.scss @@ -0,0 +1,663 @@ +@font-face { + font-family: socicon; + src: url(../fonts/socicon.woff) format("woff"); + font-weight: 400; + font-style: normal +} + +[data-icon]:before { + content: attr(data-icon) +} + +.socicon-modelmayhem:before { + content: "\e000" +} + +.socicon-mixcloud:before { + content: "\e001" +} + +.socicon-drupal:before { + content: "\e002" +} + +.socicon-swarm:before { + content: "\e003" +} + +.socicon-istock:before { + content: "\e004" +} + +.socicon-yammer:before { + content: "\e005" +} + +.socicon-ello:before { + content: "\e006" +} + +.socicon-stackoverflow:before { + content: "\e007" +} + +.socicon-persona:before { + content: "\e008" +} + +.socicon-triplej:before { + content: "\e009" +} + +.socicon-houzz:before { + content: "\e00a" +} + +.socicon-rss:before { + content: "\e00b" +} + +.socicon-paypal:before { + content: "\e00c" +} + +.socicon-odnoklassniki:before { + content: "\e00d" +} + +.socicon-airbnb:before { + content: "\e00e" +} + +.socicon-periscope:before { + content: "\e00f" +} + +.socicon-outlook:before { + content: "\e010" +} + +.socicon-coderwall:before { + content: "\e011" +} + +.socicon-tripadvisor:before { + content: "\e012" +} + +.socicon-appnet:before { + content: "\e013" +} + +.socicon-goodreads:before { + content: "\e014" +} + +.socicon-tripit:before { + content: "\e015" +} + +.socicon-lanyrd:before { + content: "\e016" +} + +.socicon-slideshare:before { + content: "\e017" +} + +.socicon-buffer:before { + content: "\e018" +} + +.socicon-disqus:before { + content: "\e019" +} + +.socicon-vkontakte:before { + content: "\e01a" +} + +.socicon-whatsapp:before { + content: "\e01b" +} + +.socicon-patreon:before { + content: "\e01c" +} + +.socicon-storehouse:before { + content: "\e01d" +} + +.socicon-pocket:before { + content: "\e01e" +} + +.socicon-mail:before { + content: "\e01f" +} + +.socicon-blogger:before { + content: "\e020" +} + +.socicon-technorati:before { + content: "\e021" +} + +.socicon-reddit:before { + content: "\e022" +} + +.socicon-dribbble:before { + content: "\e023" +} + +.socicon-stumbleupon:before { + content: "\e024" +} + +.socicon-digg:before { + content: "\e025" +} + +.socicon-envato:before { + content: "\e026" +} + +.socicon-behance:before { + content: "\e027" +} + +.socicon-delicious:before { + content: "\e028" +} + +.socicon-deviantart:before { + content: "\e029" +} + +.socicon-forrst:before { + content: "\e02a" +} + +.socicon-play:before { + content: "\e02b" +} + +.socicon-zerply:before { + content: "\e02c" +} + +.socicon-wikipedia:before { + content: "\e02d" +} + +.socicon-apple:before { + content: "\e02e" +} + +.socicon-flattr:before { + content: "\e02f" +} + +.socicon-github:before { + content: "\e030" +} + +.socicon-renren:before { + content: "\e031" +} + +.socicon-friendfeed:before { + content: "\e032" +} + +.socicon-newsvine:before { + content: "\e033" +} + +.socicon-identica:before { + content: "\e034" +} + +.socicon-bebo:before { + content: "\e035" +} + +.socicon-zynga:before { + content: "\e036" +} + +.socicon-steam:before { + content: "\e037" +} + +.socicon-xbox:before { + content: "\e038" +} + +.socicon-windows:before { + content: "\e039" +} + +.socicon-qq:before { + content: "\e03a" +} + +.socicon-douban:before { + content: "\e03b" +} + +.socicon-meetup:before { + content: "\e03c" +} + +.socicon-playstation:before { + content: "\e03d" +} + +.socicon-android:before { + content: "\e03e" +} + +.socicon-snapchat:before { + content: "\e03f" +} + +.socicon-twitter:before { + content: "\e040" +} + +.socicon-facebook:before { + content: "\e041" +} + +.socicon-googleplus:before { + content: "\e042" +} + +.socicon-pinterest:before { + content: "\e043" +} + +.socicon-foursquare:before { + content: "\e044" +} + +.socicon-yahoo:before { + content: "\e045" +} + +.socicon-skype:before { + content: "\e046" +} + +.socicon-yelp:before { + content: "\e047" +} + +.socicon-feedburner:before { + content: "\e048" +} + +.socicon-linkedin:before { + content: "\e049" +} + +.socicon-viadeo:before { + content: "\e04a" +} + +.socicon-xing:before { + content: "\e04b" +} + +.socicon-myspace:before { + content: "\e04c" +} + +.socicon-soundcloud:before { + content: "\e04d" +} + +.socicon-spotify:before { + content: "\e04e" +} + +.socicon-grooveshark:before { + content: "\e04f" +} + +.socicon-lastfm:before { + content: "\e050" +} + +.socicon-youtube:before { + content: "\e051" +} + +.socicon-vimeo:before { + content: "\e052" +} + +.socicon-dailymotion:before { + content: "\e053" +} + +.socicon-vine:before { + content: "\e054" +} + +.socicon-flickr:before { + content: "\e055" +} + +.socicon-500px:before { + content: "\e056" +} + +.socicon-instagram:before { + content: "\e057" +} + +.socicon-wordpress:before { + content: "\e058" +} + +.socicon-tumblr:before { + content: "\e059" +} + +.socicon-twitch:before { + content: "\e05a" +} + +.socicon-8tracks:before { + content: "\e05b" +} + +.socicon-amazon:before { + content: "\e05c" +} + +.socicon-icq:before { + content: "\e05d" +} + +.socicon-smugmug:before { + content: "\e05e" +} + +.socicon-ravelry:before { + content: "\e05f" +} + +.socicon-weibo:before { + content: "\e060" +} + +.socicon-baidu:before { + content: "\e061" +} + +.socicon-angellist:before { + content: "\e062" +} + +.socicon-ebay:before { + content: "\e063" +} + +.socicon-imdb:before { + content: "\e064" +} + +.socicon-stayfriends:before { + content: "\e065" +} + +.socicon-residentadvisor:before { + content: "\e066" +} + +.socicon-google:before { + content: "\e067" +} + +.socicon-yandex:before { + content: "\e068" +} + +.socicon-sharethis:before { + content: "\e069" +} + +.socicon-bandcamp:before { + content: "\e06a" +} + +.socicon-itunes:before { + content: "\e06b" +} + +.socicon-deezer:before { + content: "\e06c" +} + +[class*=" socicon-"]:before, +[class^=socicon-]:before, +[data-icon]:before { + font-family: socicon !important; + font-style: normal !important; + font-weight: 400 !important; + font-variant: normal !important; + text-transform: none !important; + speak: none; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale +} + +.c-main-nav { + position: fixed; + top: 0; + left: 0; + background-color: rgba(1, 1, 1, .95); + color: #fdfdfd; + width: 100%; + z-index: 9999; + -moz-box-shadow: 2px 2px 9px transparent; + -webkit-box-shadow: 2px 2px 9px transparent; + box-shadow: 2px 2px 9px transparent; + -moz-transform: translate(0, -100%); + -ms-transform: translate(0, -100%); + -webkit-transform: translate(0, -100%); + transform: translate(0, -100%); + -moz-transition: -moz-transform 1s; + -o-transition: -o-transform 1s; + -webkit-transition: -webkit-transform 1s; + transition: all 1s ease-out; + opacity: 0; +} + +.c-main-nav.active { + -moz-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -webkit-transform: translate(0, 0); + transform: translate(0, 0); + -moz-box-shadow: 2px 2px 9px rgba(0, 0, 0, .4); + -webkit-box-shadow: 2px 2px 9px rgba(0, 0, 0, .4); + box-shadow: 2px 2px 9px rgba(0, 0, 0, .4); + opacity: 1; +} + +.c-main-nav__list { + list-style-type: none; + font-size: 1.5rem; + padding: 0; + margin: 0 +} + +.c-main-nav__item { + text-align: center; + font-weight: 300; + padding: 0 +} + +.c-main-nav__link { + color: #fdfdfd; + display: block; + padding: 12px 0; + margin: 0; + width: 100%; + height: 100%; + text-decoration: none; +} + +.c-main-nav__link:hover { + background-color: #00f596; + color: #111 +} + +.c-main-nav__item:last-of-type .c-main-nav__link { + color: #00f596 +} + +.c-main-nav__item:last-of-type .c-main-nav__link:hover { + background-color: transparent; + color: #00f596 +} + +@media (max-height:575px) { + .c-main-nav__list { + font-size: 1.5rem + } + + .c-main-nav__link { + padding: 9px 0 + } +} + + +.c-mobile-trigger { + position: fixed; + top: 15px; + right: 15px; + padding: 5px 10px; + z-index: 1000; + box-shadow: 2px 2px 10px rgba(0,0,0,0.2); + background-color: rgba(0,0,0,1); + display: block; + + &__link { + color: white!important; + font-weight: 400; + text-decoration: none; + font-weight: 400; + } +} + +.page-header { + position: fixed; + background-color: #111; + padding: 10px 30px; + width: 100%; + color: #fdfdfd; + z-index: 9998 +} + +.page-header .subtitle { + font-size: 1.2rem; + letter-spacing: 1px; + margin-left: 7px; + color: #00f596 +} + +@media (max-width:650px) { + .page-header .subtitle { + display: none + } +} + +.page-header a, +.page-header a:active, +.page-header a:visited { + color: #fdfdfd; + text-decoration: none; + +} + +.page-header a.home-link, +.page-header a:active.home-link, +.page-header a:visited.home-link { + font-family: mohave; + font-size: 2rem; + letter-spacing: 3px; + text-transform: uppercase; + font-weight: 300; +} + +.page-header .open-menu-wrapper { + float: right; + display: inline-block; + position: absolute; + right: 15px; + top: 50%; + transform: translateY(-50%) +} + +.page-header .open-menu { + font-size: 1.3rem; + line-height: 0; + height: 1.5rem; + padding: 2px 3px +} + +.page-header ul.social-container { + float: right; + display: inline-block; + list-style: none; + font-size: 1.2rem; + padding: 0; + margin: 0; + position: absolute; + right: 115px; + top: 51%; + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -webkit-transform: translateY(-50%); + transform: translateY(-50%) +} + +.page-header ul.social-container li { + display: inline-block +} + +.page-header ul.social-container a { + display: inline-block; + width: 25px; + position: relative +} + +.page-header ul.social-container a span { + position: relative +} + +.bg-hr, +.bg-stretch { + position: absolute; + width: 100% +} + +.page-header ul.social-container a .socicon-facebook { + font-size: .95rem; + top: -2px; + left: 6px; +} + +@media (max-width:740px) { + .page-header ul.social-container { + display: none + } +} \ No newline at end of file diff --git a/src/sass/_mixins.scss b/src/sass/_mixins.scss new file mode 100644 index 0000000..20298b0 --- /dev/null +++ b/src/sass/_mixins.scss @@ -0,0 +1,4 @@ +@mixin font-size($sizeValue) { + font-size: $sizeValue + px; + font-size: ($sizeValue / 16) + rem; +} \ No newline at end of file diff --git a/src/sass/_order.scss b/src/sass/_order.scss new file mode 100644 index 0000000..626cce2 --- /dev/null +++ b/src/sass/_order.scss @@ -0,0 +1,289 @@ +.c-products { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-column-gap: 25px; + grid-row-gap: 25px; + + @media (max-width: 900px) { + grid-template-columns: repeat(1, 1fr); + } +} + +.c-product { + + &__name { + font-weight: 500; + margin-bottom: 10px; + } + &__order { + display: flex; + justify-content: start; + } + + &__input { + border: 0; + border-bottom: 1px solid #111; + font-size: 20px; + font-weight: 500; + font-family: 'Roboto'; + width: 50px; + margin-left: 5px; + &:focus { + border-color: $primary; + } + } + + &__img { + max-width: 100%; + margin-bottom: 5px; + } + + &__price { + margin-right: 5px; + } +} + +form { + width: 100%; +} + +.c-order-info { + margin: 25px 0; +} + +.c-form-row { + display: block; + width: 100%; + margin-bottom: 25px; +} + + +.c-error { + @extend .t-p1; + color: white; + padding: 10px; + background-color: red; + font-weight: 400; + display: block; + +} + +.c-label { + font-weight: 400; + display: block; + margin-bottom: 10px; +} + +.c-input { + $this: &; + border: 0; + outline: 0; + padding-bottom: 5px; + border-bottom: 1px solid rgba(0,0,0,0.2); + font-family: 'Roboto', sans-serif; + font-size: 20px; + width: 100%; + font-weight: 200; + + &:focus { + border-bottom: 1px solid rgba(0,0,0,0.8); + } + + transition: border-color 200ms ease-out; + + &:read-only { + margin-left: -2px; + border-bottom: 0; + &:focus { + border-bottom: 0; + } + } +} + +.c-select { + position: relative; + &__select { + $this: &; + border: 0; + outline: 0; + padding-bottom: 5px; + border: 1px solid rgba(0,0,0,0.2); + font-family: 'Roboto', sans-serif; + font-size: 20px; + width: 100%; + font-weight: 200; + padding: 10px; + // border-bottom: 1px solid rgba(0,0,0,0.8); + appearance: none; + transition: border-color 200ms ease-out; + position: relative; + } + + &:after { + content: ""; + display: block; + position: absolute; + width: 14px; + height: 14px; + top: 15px; + right: 12px; + background-image: url(/static/img/caret.png); + background-size: cover; + } + // &:read-only { + // margin-left: -2px; + // border-bottom: 0; + // &:focus { + // border-bottom: 0; + // } + // } + +} + +.o-input-select-margin input { + margin-top: 14px; +} + +.c-grid { + display: grid; + grid-template-columns: 50% 50%; + grid-column-gap: 50px; + + @media (max-width: 900px) { + div:last-of-type { + margin-top: 25px; + } + grid-template-columns: 100%; + } +} + +.c-col { + // width: 50%; +} + +.c-product-container { + display: flex; + + @media (max-width: 700px) { + display: block; + } +} + +.c-button-container { + margin: 40px 0; +} + + + +.c-button { + $this: &; + padding: 15px 45px; + background-color: black; + color: white!important; + text-decoration: none; + border: 0; + outline: 0; + font-weight: 400; + cursor: pointer; + + font-family: 'Roboto', sans-serif; + font-size: 16px; + text-transform: uppercase; + transition: all 300ms ease-out; + + &:hover { + background-color: $primary; + } + + @media (max-width: 700px) { + width: 100%; + display: block; + text-align: center; + } +} + +// .c-product { +// $this: &; +// padding: 25px 0; +// margin-right: 50px; + +// &:last-of-type { +// margin-right: 0; +// } +// &__img { +// display: block; +// width: 250px; +// margin: 15px 0; +// } + +// &__x { +// height: 31px; +// display: inline-block; +// } + +// &__title { +// display: inline-block; +// text-transform: uppercase; +// font-weight: 400; +// } +// &__price { +// display: block; +// } + +// &__input { +// padding: 5px; +// border: 1px solid rgba(0,0,0,0.2)!important; +// width: 43px; + +// &:focus { +// border: 1px solid rgba(0,0,0,0.8)!important; +// } + +// transition: border-color 200ms ease-out; +// } + +// &__order-info { +// display: flex; +// align-items: center; +// span { +// margin-right: 10px; +// }; +// } + +// @media (max-width: 700px) { +// width: 100%; +// margin-right: 0; + +// #{$this}__img { +// width: 100%; +// } +// } +// } + +.c-price-order { + +} + +.c-price-table { + width: 100%; + td { + padding: 0px 0; + } + + &__right { + text-align: right; + } + + &__top { + td { + padding-top: 15px; + } + } + + &__underline { + border-bottom: 1px solid black; + td { + padding-bottom: 15px; + } + } +} \ No newline at end of file diff --git a/src/sass/_reset.scss b/src/sass/_reset.scss new file mode 100644 index 0000000..b2ee146 --- /dev/null +++ b/src/sass/_reset.scss @@ -0,0 +1,52 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +html * { + box-sizing: border-box; +} \ No newline at end of file diff --git a/src/sass/_typography.scss b/src/sass/_typography.scss new file mode 100644 index 0000000..b452d50 --- /dev/null +++ b/src/sass/_typography.scss @@ -0,0 +1,35 @@ +.t-h1 { + font-family: mohave; + display: block; + font-size: 5rem; + margin: 0 0 15px 0; + font-weight: 400; + text-transform: uppercase; +} + +p, .t-p1 { + display: block; + margin-block-start: 1rem; + margin-block-end: 1rem; + margin-inline-start: 0px; + margin-inline-end: 0px; +} + +.t-h2 { + font-family: mohave; + display: block; + font-size: 1.6rem; + margin: 0 0 15px 0; + font-weight: 400; + text-transform: uppercase; +} + +.t-h3 { + display: block; + font-size: 1.1rem; + margin-block-start: 0.67rem; + margin-block-end: 0.67rem; + margin-inline-start: 0px; + margin-inline-end: 0px; + font-weight: bold; +} \ No newline at end of file diff --git a/src/sass/index.scss b/src/sass/index.scss new file mode 100644 index 0000000..129d169 --- /dev/null +++ b/src/sass/index.scss @@ -0,0 +1,99 @@ +@import "reset"; +@import "mixins"; +@import "color"; +@import "typography"; +@import "order"; +@import "menu"; + +body { + /* text-transform: uppercase; */ + font-family: 'Roboto', sans-serif; + font-size: 20px; + padding: 0; + margin: 0; + line-height: 1.4; + font-weight: 100; + color: $black; +} + +main { + min-height: calc(100vh - 58px); + padding-top: 75px; +} + +// table { +// height: 100vh; +// width: 100%; +// } + + + + +.c-link, .c-link:hover, .c-link:visited { + color: black; + font-weight: 300; +} + +.main { + background-image: url('/static/img/alex.jpg'); + background-size: cover; + background-position: center center; + background-repeat: no-repeat; + min-height: 100vh; +} + +.c-section { + padding: 50px; +} + +@media (max-width: 1024px) { + .c-section { + padding: 25px 15px; + } +} + +.c-section__content { + max-width: 960px; + margin: auto; +} + +ul {list-style: none; padding: 0;} +li { + line-height: 1.4; +} + + +.c-auto-ratio__inner { + padding-top: 56.25%; + position: relative; +} + +.c-auto-ratio__inner iframe { + position: absolute; + top:0; + left: 0; + width: 100%; + height: 100%; +} + +.c-footer { + background-color: black; + padding: 15px; +} + +.c-footer ul { + margin: auto; + text-align: center; +} + +.c-footer__item { + color: white; + font-size: 12px; + display: inline-block; + margin-right: 15px; +} + +.c-footer__item a { + color: white!important; + text-decoration: none; +} \ No newline at end of file diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..63b29e8 --- /dev/null +++ b/templates/404.html @@ -0,0 +1,11 @@ +{{define "body"}} +
+
+
+

404

+

The page you trying to find is no longer there.

+

Back to shop

+
+
+
+{{end}} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..ae217a0 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,73 @@ + + + + + + + Thomas Pol Shop + + + + + + + + + + {{template "body" .}} + + + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..7b8acc1 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,32 @@ +{{define "body"}} +
+
+
+

+ Shop +

+

+ Welcome to the T.Pol shop! My solo album 'Blue Soil' is fresh out on vinyl and it sounds great. My debut album 'In America' is on sale and discounted when you order the Vinyl! Enjoy my music and thank you very much. +

+
+
+ {{range .products}} +
+

{{.Name}}

+ +
+ {{formatMoney .Price}} + × + +
+
+ {{end}} +
+
+ +
+
+
+
+
+{{end}} diff --git a/templates/order_checkout.html b/templates/order_checkout.html new file mode 100644 index 0000000..797fb40 --- /dev/null +++ b/templates/order_checkout.html @@ -0,0 +1,76 @@ +{{define "body"}} +
+
+
+
+ {{range $k, $v := .order}} + + {{end}} +

Order summary

+ +
+
+ + {{range $k, $v := .order}} + {{if gt $v 0}} + {{$prod := getProd $k $.products}} + + + + + {{end}} + {{end}} +
{{$prod.Name}} × {{$v}}{{formatMoney (mult $prod.Price $v)}}
+
+
+ {{if ne .error ""}} +
+ {{.error}} +
+ {{end}} +
+

Shipping info

+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ +
+ +
+
+
+
+ + +
+
+
+
+{{end}} \ No newline at end of file diff --git a/templates/order_index.html b/templates/order_index.html new file mode 100644 index 0000000..9b0055f --- /dev/null +++ b/templates/order_index.html @@ -0,0 +1,52 @@ +{{define "body"}} +
+
+
+

Store

+ {{if ne .error ""}} +

{{.error}}

+ {{end}} +
+

At the moment we only ship within the Netherlands. If you live outside the Netherlands and would like to receive the album please send an email to info@alexandervanpopta.nl.

+
    + {{range .products}} +
  • + {{.Name}} + +
    + {{formatMoney .Price}} × + +
    +
  • + {{end}} +
+

Order info

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+{{end}} diff --git a/templates/order_info.html b/templates/order_info.html new file mode 100644 index 0000000..15f8304 --- /dev/null +++ b/templates/order_info.html @@ -0,0 +1,58 @@ +{{define "body"}} +
+
+
+
+ {{range $k, $v := .order}} + + {{end}} +

Order summary

+
+
+ + {{range $k, $v := .order}} + {{if gt $v 0}} + {{$prod := getProd $k $.products}} + + + + + {{end}} + {{end}} + + + + + + + + +
{{$prod.Name}} × {{$v}}{{formatMoney (mult $prod.Price $v)}}
{{.shippingLabel}}{{formatMoney .shippingCost}}
Total{{formatMoney .total}}
+
+
+
+

Shipping info

+ +
+ + + + + +
+ +
+ + + + + + + +
+ + +
+
+
+{{end}} \ No newline at end of file diff --git a/templates/order_pending.html b/templates/order_pending.html new file mode 100644 index 0000000..fa3f876 --- /dev/null +++ b/templates/order_pending.html @@ -0,0 +1,36 @@ +{{define "body"}} +
+
+
+ {{if eq .payment.Status "open"}} +

Processing payment

+ {{else}} +
+

Your payment failed

+ +
+ {{end}} +
+
+
+ + +{{end}} \ No newline at end of file diff --git a/templates/order_thankyou.html b/templates/order_thankyou.html new file mode 100644 index 0000000..757f4f4 --- /dev/null +++ b/templates/order_thankyou.html @@ -0,0 +1,16 @@ +{{define "body"}} +
+
+
+

+ Thank you for ordering my music and I hope you enjoy it! +

+

+ Yours truly,
+ Thomas Pol +

+

HOME

+
+
+
+{{end}} \ No newline at end of file diff --git a/templates/preorder.email b/templates/preorder.email new file mode 100644 index 0000000..0c78cf2 --- /dev/null +++ b/templates/preorder.email @@ -0,0 +1,8 @@ +

Dear {{.preOrder.Name}},

+

 

+

Thank you for your order! I will ship your order as soon as possible.

+

 

+

For questions regarding your order you can contact me at info@thomaspol.com

+

 

+

Yours truly,

+

Thomas Pol

\ No newline at end of file diff --git a/templates/preorder_admin.email b/templates/preorder_admin.email new file mode 100644 index 0000000..388e8d8 --- /dev/null +++ b/templates/preorder_admin.email @@ -0,0 +1,31 @@ +{{define "tpl"}} + + + + + + + + + + + + + + + + + +
NaamEmailStraatnaam + nrPostcodeStadLand
{{.preOrder.Name}}{{.preOrder.Email}}{{.preOrder.Address}}{{.preOrder.Postcode}}{{.preOrder.City}}{{index countries .preOrder.Country}}
+ + + + + +{{range .preOrder.Items}} + + + +{{end}} +
Producten
{{.Product.Name}}
+{{end}} diff --git a/templates/song.html b/templates/song.html new file mode 100644 index 0000000..f4fe1e3 --- /dev/null +++ b/templates/song.html @@ -0,0 +1,48 @@ + + + + + + + Document + + + + + +
+
+ terug +
+

+ {{.album.Name}} ({{.album.Release}}) +

+
+

+ {{.song.Title}} +

+
+ {{range .song.Lyrics}} +
+                {{- . -}}
+            
+ {{end}} +
+
+ + + + + + \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..7b1cec0 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,50 @@ +const webpack = require('webpack'); +const path = require('path'); + + +const srcPath = path.join(__dirname, 'src'); +const srcJsPath = path.join(srcPath, 'js'); + +const destPath = path.join(__dirname, 'dist'); +const destJsPath = path.join(destPath, 'js'); + +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); + +const env = process.env.NODE_ENV || 'production'; + +const config = { + watch: env !== 'production', + entry: { + "shared": srcJsPath + '/shared', + }, + output: { + path: destJsPath, + filename: '[name].js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + presets: ['es2015'] + } + } + } + ] + }, + stats: { + colors: true + }, + plugins: [] +} + +if (env === 'production') { + config.plugins.push( + new UglifyJsPlugin() + ) +} + +module.exports = config; \ No newline at end of file