M Makefile => Makefile +2 -2
@@ 1,4 1,4 @@
-# Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+# Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
#
# This file is part of web.
#
@@ 84,7 84,7 @@ install:
deb-dependencies:
@sudo apt-get install -y debian-archive-keyring build-essential autoconf autotools-dev git-buildpackage dh-make dh-golang golang-go
@if [ ! -f /usr/bin/go ]; then \
- ln -s /usr/lib/go-1.19/bin/go /usr/bin/go ; \
+ ln -s /usr/lib/go-1.20/bin/go /usr/bin/go ; \
fi
@if [ ! -f /var/cache/pbuilder/base.cow ]; then \
DIST=testing git-pbuilder create --mirror=http://ftp.es.debian.org/debian ; \
M go.mod => go.mod +8 -8
@@ 1,11 1,11 @@
module git.sr.ht/~ritho/rweb
-go 1.19
+go 1.20
require (
- github.com/golang/glog v1.0.0
- github.com/labstack/echo/v4 v4.9.1
- golang.org/x/crypto v0.3.0
+ github.com/golang/glog v1.1.1
+ github.com/labstack/echo/v4 v4.10.2
+ golang.org/x/crypto v0.9.0
gopkg.in/yaml.v2 v2.4.0
)
@@ 13,11 13,11 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/mattn/go-isatty v0.0.18 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
- golang.org/x/net v0.2.0 // indirect
- golang.org/x/sys v0.3.0 // indirect
- golang.org/x/text v0.5.0 // indirect
+ golang.org/x/net v0.10.0 // indirect
+ golang.org/x/sys v0.8.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
)
M go.sum => go.sum +17 -30
@@ 3,55 3,42 @@ 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/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
-github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
-github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
-github.com/labstack/echo/v4 v4.8.0 h1:wdc6yKVaHxkNOEdz4cRZs1pQkwSXPiRjq69yWP4QQS8=
-github.com/labstack/echo/v4 v4.8.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
-github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
-github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
-github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
-github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw=
+github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
+github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
+github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
+github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-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.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
-golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY=
-golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
-golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
-golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
@@ 59,5 46,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
M internal/config/config.go => internal/config/config.go +9 -9
@@ 1,7 1,7 @@
// Package config implements the web configurations.
package config
-/* Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 40,14 40,14 @@ type Server struct {
// Section has a specific section configurations.
type Section struct {
- Name string `yaml:"name"`
- Path string `yaml:"path"`
- Type string `yaml:"type"`
- Title string `yaml:"title"`
- Description string `yaml:"description"`
- Javascripts []string `yaml:"javascripts"`
- CSS []string `yaml:"css"`
- Extra map[string]interface{} `yaml:"extra"`
+ Name string `yaml:"name"`
+ Path string `yaml:"path"`
+ Type string `yaml:"type"`
+ Title string `yaml:"title"`
+ Description string `yaml:"description"`
+ Javascripts []string `yaml:"javascripts"`
+ CSS []string `yaml:"css"`
+ Extra map[string]any `yaml:"extra"`
}
// Project contains the project information for the list of projects.
M internal/engine/pages/blog/blog.go => internal/engine/pages/blog/blog.go +5 -5
@@ 1,7 1,7 @@
// Package blog contains generates a blog page.
package blog
-/* Copyright (C) 2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2022-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 46,7 46,7 @@ type Blog struct {
content string
notFound string
name string
- params map[string]interface{}
+ params map[string]any
tmpl *template.Template
}
@@ 78,9 78,9 @@ func (b *Blog) WithContent(content string) pages.Page {
}
// WithParam add a new parameter to the web page.
-func (b *Blog) WithParam(name string, value interface{}) pages.Page {
+func (b *Blog) WithParam(name string, value any) pages.Page {
if b.params == nil {
- b.params = make(map[string]interface{}, 1)
+ b.params = make(map[string]any, 1)
}
b.params[name] = value
@@ 193,7 193,7 @@ func (b *Blog) Render() (string, error) {
}
if b.params == nil {
- b.params = make(map[string]interface{}, 1)
+ b.params = make(map[string]any, 1)
}
b.params["page"] = content.Content{
M internal/engine/pages/blog/post/post.go => internal/engine/pages/blog/post/post.go +2 -2
@@ 1,7 1,7 @@
// Package post implements the post model.
package post
-/* Copyright (C) 2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2022-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 44,7 44,7 @@ func (a *Post) Content() string {
glog.Errorf("Error rendenring the article: %s", err)
}
- err = r.Render(&content, "body", map[string]interface{}{
+ err = r.Render(&content, "body", map[string]any{
"body": articleBuffer.String(),
}, nil)
if err != nil {
M internal/engine/pages/blog/section/section.go => internal/engine/pages/blog/section/section.go +3 -3
@@ 1,7 1,7 @@
// Package section implements the blog sections for the html template.
package section
-/* Copyright (C) 2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2022-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 192,7 192,7 @@ func (s *Section) Content() string {
}
r := renderer.New(s.info.assetsPath)
- err := r.Render(&articlesBuffer, "articles", map[string]interface{}{
+ err := r.Render(&articlesBuffer, "articles", map[string]any{
"Articles": articles,
"Categories": s.info.categories,
"Pages": s.info.pages,
@@ 204,7 204,7 @@ func (s *Section) Content() string {
log.Printf("Error rendenring the list of articles: %s", err)
}
- err = r.Render(&content, "body", map[string]interface{}{
+ err = r.Render(&content, "body", map[string]any{
"body": articlesBuffer.String(),
}, nil)
if err != nil {
M internal/engine/pages/pages.go => internal/engine/pages/pages.go +2 -2
@@ 1,7 1,7 @@
// Package pages contains all the web page types for the web.
package pages
-/* Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 21,6 21,6 @@ package pages
// Page represents a web page to render.
type Page interface {
WithContent(string) Page
- WithParam(string, interface{}) Page
+ WithParam(string, any) Page
Render() (string, error)
}
M internal/engine/pages/projects/projects.go => internal/engine/pages/projects/projects.go +7 -7
@@ 2,7 2,7 @@
// for the web.
package projects
-/* Copyright (C) 2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2022-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 40,7 40,7 @@ type Static struct {
content string
notFound string
name string
- params map[string]interface{}
+ params map[string]any
tmpl *template.Template
}
@@ 71,9 71,9 @@ func (s *Static) WithContent(content string) pages.Page {
}
// WithParam add a new parameter to the web page.
-func (s *Static) WithParam(name string, value interface{}) pages.Page {
+func (s *Static) WithParam(name string, value any) pages.Page {
if s.params == nil {
- s.params = make(map[string]interface{}, 1)
+ s.params = make(map[string]any, 1)
}
s.params[name] = value
@@ 92,7 92,7 @@ func (s *Static) body() (string, error) {
sections[project.Section] = append(sections[project.Section], project)
}
- params := map[string]interface{}{
+ params := map[string]any{
"sections": sections,
"url": "/" + s.name,
}
@@ 103,7 103,7 @@ func (s *Static) body() (string, error) {
p := strings.Split(s.content, "/")
for i := range s.cfg.Projects {
if s.cfg.Projects[i].Name == p[1] {
- params = map[string]interface{}{
+ params = map[string]any{
"parent": "/" + s.name,
"project": s.cfg.Projects[i],
}
@@ 137,7 137,7 @@ func (s *Static) Render() (string, error) {
}
if s.params == nil {
- s.params = make(map[string]interface{}, 1)
+ s.params = make(map[string]any, 1)
}
s.params["page"] = content.Content{
M internal/engine/pages/static/static.go => internal/engine/pages/static/static.go +5 -5
@@ 1,7 1,7 @@
// Package static contains a static page for the web.
package static
-/* Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 44,7 44,7 @@ type Static struct {
content string
notFound string
name string
- params map[string]interface{}
+ params map[string]any
tmpl *template.Template
}
@@ 75,9 75,9 @@ func (s *Static) WithContent(content string) pages.Page {
}
// WithParam add a new parameter to the web page.
-func (s *Static) WithParam(name string, value interface{}) pages.Page {
+func (s *Static) WithParam(name string, value any) pages.Page {
if s.params == nil {
- s.params = make(map[string]interface{}, 1)
+ s.params = make(map[string]any, 1)
}
s.params[name] = value
@@ 115,7 115,7 @@ func (s *Static) Render() (string, error) {
}
if s.params == nil {
- s.params = make(map[string]interface{}, 1)
+ s.params = make(map[string]any, 1)
}
s.params["page"] = content.Content{
M internal/server/errors/errors.go => internal/server/errors/errors.go +2 -2
@@ 1,7 1,7 @@
// Package errors manage the web error handler.
package errors
-/* Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 32,7 32,7 @@ func Handler(err error, c echo.Context) {
code = he.Code
}
- rerr := c.Render(code, fmt.Sprintf("%d", code), map[string]interface{}{
+ rerr := c.Render(code, fmt.Sprintf("%d", code), map[string]any{
"title": "Error",
})
if rerr != nil {
M internal/server/renderer/renderer.go => internal/server/renderer/renderer.go +3 -3
@@ 1,7 1,7 @@
// Package renderer implements the html renderer.
package renderer
-/* Copyright (C) 2021-2022 Pablo Alvarez de Sotomayor Posadillo
+/* Copyright (C) 2021-2023 Pablo Alvarez de Sotomayor Posadillo
This file is part of web.
@@ 45,11 45,11 @@ func New(assetsPath string) echo.Renderer {
}
// Render the templates.
-func (r *render) Render(w io.Writer, name string, data interface{},
+func (r *render) Render(w io.Writer, name string, data any,
ec echo.Context,
) error {
// Add global methods if data is a map
- if viewContext, isMap := data.(map[string]interface{}); isMap && ec != nil {
+ if viewContext, isMap := data.(map[string]any); isMap && ec != nil {
viewContext["reverse"] = ec.Echo().Reverse
}