Skip to content

Commit

Permalink
feat: Add more template function to generator context (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabyx authored Feb 7, 2022
1 parent 67e5244 commit c02be24
Show file tree
Hide file tree
Showing 109 changed files with 15,312 additions and 16 deletions.
13 changes: 1 addition & 12 deletions 3_transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,6 @@ func generateCommitHashURL(remoteURL *url.URL, longHash string) string {
}
}

func paddingLeft(txt string, cur string) string {
lines := strings.Split(txt, "\n")
newArr := make([]string, 0)

for _, line := range lines {
newArr = append(newArr, cur+line)
}

return strings.Join(newArr, "\n")
}

var githubOrgRegex = regexp.MustCompile(`^([^@]+)@github\.com:(\w+)\/(.+)$`)

func Transform(g *client.GitClient, splices []*ExtractSplice) ([]*TemplateContext, error) {
Expand Down Expand Up @@ -205,7 +194,7 @@ func Transform(g *client.GitClient, splices []*ExtractSplice) ([]*TemplateContex
c.Field.Footer = &Footer{
BreakingChange: &BreakingChange{
Title: breakingChangeFooter.Title,
Content: paddingLeft(breakingChangeFooter.Content, " "),
Content: breakingChangeFooter.Content,
},
}
}
Expand Down
143 changes: 143 additions & 0 deletions 4_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"fmt"
"html/template"
"io/ioutil"
"regexp"

"github.com/Masterminds/sprig/v3"

"github.com/pkg/errors"
"github.com/release-lab/whatchanged/internal/client"
Expand All @@ -15,7 +18,141 @@ import (
//go:embed template/*.tpl
var TemplateFS embed.FS

// Get all regex functions which use a compiled regex cache.
func getRegexFuncs(regexCache map[string]*regexp.Regexp) template.FuncMap {
return map[string]interface{}{
// Regex (but cached)

"regexMatch": func(regex string, s string) bool {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.MatchString(s)
},

"mustRegexMatch": func(regex string, s string) (bool, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return false, err
}
regexCache[regex] = r
}
return r.MatchString(s), nil
},

"regexFindAll": func(regex string, s string, n int) []string {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.FindAllString(s, n)
},

"mustRegexFindAll": func(regex string, s string, n int) ([]string, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return []string{}, err
}
regexCache[regex] = r
}
return r.FindAllString(s, n), nil
},

"regexFind": func(regex string, s string) string {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.FindString(s)
},

"mustRegexFind": func(regex string, s string) (string, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return "", err
}
regexCache[regex] = r
}
return r.FindString(s), nil
},

"regexReplaceAll": func(regex string, s string, repl string) string {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.ReplaceAllString(s, repl)
},

"mustRegexReplaceAll": func(regex string, s string, repl string) (string, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return "", err
}
regexCache[regex] = r
}
return r.ReplaceAllString(s, repl), nil
},

"regexReplaceAllLiteral": func(regex string, s string, repl string) string {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.ReplaceAllLiteralString(s, repl)
},

"mustRegexReplaceAllLiteral": func(regex string, s string, repl string) (string, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return "", err
}
regexCache[regex] = r
}
return r.ReplaceAllLiteralString(s, repl), nil
},

"regexSplit": func(regex string, s string, n int) []string {
r, exists := regexCache[regex]
if !exists {
r = regexp.MustCompile(regex)
regexCache[regex] = r
}
return r.Split(s, n)
},

"mustRegexSplit": func(regex string, s string, n int) ([]string, error) {
r, exists := regexCache[regex]
if !exists {
r, err := regexp.Compile(regex)
if err != nil {
return []string{}, err
}
regexCache[regex] = r
}
return r.Split(s, n), nil
},
}
}

func GenerateFromContext(g *client.GitClient, contexts []*TemplateContext, format EnumFormat, preset EnumPreset, templateFile string, templateStr string) ([]byte, error) {

switch format {
case FormatJSON:
output, err := json.Marshal(contexts)
Expand All @@ -26,6 +163,7 @@ func GenerateFromContext(g *client.GitClient, contexts []*TemplateContext, forma

return output, nil
case FormatMarkdown:

var output []byte

if templateStr != "" {
Expand Down Expand Up @@ -56,12 +194,17 @@ func GenerateFromContext(g *client.GitClient, contexts []*TemplateContext, forma
for _, ctx := range contexts {
t := template.New(ctx.Version)

t.Funcs(sprig.FuncMap())
t.Funcs(template.FuncMap{
"unescape": func(s string) template.HTML {
return template.HTML(s)
},
})

// Overwrite regex function with cached one for better performance.
regexCache := make(map[string]*regexp.Regexp)
t.Funcs(getRegexFuncs(regexCache))

if t, err := t.Parse(templateStr); err != nil {
return nil, errors.WithStack(err)
} else {
Expand Down
5 changes: 3 additions & 2 deletions CUSTOM_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ There are 3 parts in Context
14. **BreakingChanges**: the `commit` list of `revert` which includes `BREAKING CHANGES: xxx` in commit message body
15. **Commits**: all `commit` of generation

2. Method
2. Methods

1. **unescape(text string)**: unescape the string
1. **unescape(text string)**: unescape the string `text`.
2. All functions from the library [sprig](https://github.com/Masterminds/sprig)

source code:

Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.17

require (
github.com/88250/lute v1.7.3
github.com/Masterminds/sprig/v3 v3.2.2
github.com/blang/semver/v4 v4.0.0
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/go-git/go-git/v5 v5.4.2
Expand All @@ -14,6 +15,8 @@ require (
)

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Microsoft/go-winio v0.4.16 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
Expand All @@ -24,15 +27,21 @@ require (
github.com/emirpasic/gods v1.12.0 // indirect
github.com/go-git/gcfg v1.5.0 // indirect
github.com/go-git/go-billy/v5 v5.3.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20210619142842-05447a1fa367 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/onsi/ginkgo v1.16.4 // indirect
github.com/onsi/gomega v1.16.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
Expand Down
24 changes: 24 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ github.com/88250/lute v1.7.3 h1:Yuve6dTAZNjWktXpHK14PND4KaBwqVxVi3L+GZa3+HQ=
github.com/88250/lute v1.7.3/go.mod h1:3CPco034YZBxszJEqBPNgp3a1K+uddq4IegStqBiyTM=
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/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
Expand Down Expand Up @@ -124,6 +130,9 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
Expand Down Expand Up @@ -154,6 +163,10 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
Expand Down Expand Up @@ -189,6 +202,9 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
Expand All @@ -197,6 +213,9 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
Expand Down Expand Up @@ -243,6 +262,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
Expand All @@ -255,6 +276,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
Expand Down Expand Up @@ -290,6 +313,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
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-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
Expand Down
2 changes: 1 addition & 1 deletion template/default.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

- {{if .Field.Footer.BreakingChange.Title}}{{ unescape .Field.Footer.BreakingChange.Title }}{{ else }}{{ unescape .Field.Title }}{{ end }}

{{ unescape .Field.Footer.BreakingChange.Content }}
{{ .Field.Footer.BreakingChange.Content | indent 2 | unescape }}

{{ end -}}
{{ end }}
2 changes: 1 addition & 1 deletion template/full.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

- {{if .Field.Footer.BreakingChange.Title}}{{ unescape .Field.Footer.BreakingChange.Title }}{{ else }}{{ unescape .Field.Title }}{{ end }}

{{ unescape .Field.Footer.BreakingChange.Content }}
{{ .Field.Footer.BreakingChange.Content | indent 2 | unescape }}

{{ end -}}
{{ end }}
18 changes: 18 additions & 0 deletions vendor/github.com/Masterminds/goutils/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions vendor/github.com/Masterminds/goutils/CHANGELOG.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c02be24

Please sign in to comment.