Damien Mathieu
2c15a77942
Fix lint issues for golangci-lint 1.62.0 ( #5967 )
...
This fixes the new lint issues brough by the golangci-lint upgrade in
https://github.com/open-telemetry/opentelemetry-go/pull/5966
2024-11-13 08:58:59 +01:00
Matthieu MOREL
6edc7a63df
[chore]: enable expected-actual rule from testifylint ( #5848 )
...
Testifylint is a linter that provides best practices with the use of
testify.
This PR enables
[expected-actual](https://github.com/Antonboom/testifylint?tab=readme-ov-file#expected-actual )
rule from [testifylint](https://github.com/Antonboom/testifylint )
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2024-09-26 12:04:33 +02:00
Matthieu MOREL
063239fa37
[chore]: enable len and empty rules from testifylint ( #5832 )
...
#### Description
Testifylint is a linter that provides best practices with the use of
testify.
This PR enables
[empty](https://github.com/Antonboom/testifylint?tab=readme-ov-file#empty )
and
[len](https://github.com/Antonboom/testifylint?tab=readme-ov-file#len )
rules from [testifylint](https://github.com/Antonboom/testifylint )
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2024-09-21 08:04:28 -07:00
Damien Mathieu
38dfcb2330
Ensure codespell failures fail CI ( #5761 )
...
With the `write` option, codespell fixes issues (which is a nice
behavior when we run it locally), but it also returns a 0 status code
(except if some failures couldn't be fixed).
So in order to actually fix the CI on a failing codespell, we need to
ensure the working directory is clean.
2024-09-03 14:50:17 +02:00
Sam Xie
d61bbf18f5
baggage: Accept non-ASCII keys ( #5132 )
...
resolves #4946
I also add additional test cases to cover more lines.
benchmark results:
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
New-10 402.3n ± 1% 422.4n ± 6% +4.98% (p=0.000 n=10)
NewMemberRaw-10 10.82n ± 0% 13.90n ± 1% +28.51% (p=0.000 n=10)
Parse-10 803.8n ± 1% 795.0n ± 1% -1.09% (p=0.011 n=10)
String-10 682.6n ± 0% 610.0n ± 2% -10.63% (p=0.000 n=10)
ValueEscape/nothing_to_escape-10 4.856n ± 0% 4.849n ± 0% ~ (p=0.279 n=10)
ValueEscape/requires_escaping-10 22.47n ± 1% 22.36n ± 1% ~ (p=0.342 n=10)
ValueEscape/long_value-10 513.3n ± 1% 510.1n ± 0% -0.62% (p=0.006 n=10)
MemberString-10 430.8n ± 2% 471.3n ± 2% +9.41% (p=0.000 n=10)
geomean 124.5n 128.5n +3.22%
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
New-10 704.0 ± 0% 704.0 ± 0% ~ (p=1.000 n=10) ¹
NewMemberRaw-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
Parse-10 888.0 ± 0% 888.0 ± 0% ~ (p=1.000 n=10) ¹
String-10 936.0 ± 0% 840.0 ± 0% -10.26% (p=0.000 n=10)
ValueEscape/nothing_to_escape-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10 16.00 ± 0% 16.00 ± 0% ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10 576.0 ± 0% 576.0 ± 0% ~ (p=1.000 n=10) ¹
MemberString-10 656.0 ± 0% 656.0 ± 0% ~ (p=1.000 n=10) ¹
geomean ² -1.34% ²
¹ all samples are equal
² summaries must be >0 to compute geomean
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
New-10 8.000 ± 0% 8.000 ± 0% ~ (p=1.000 n=10) ¹
NewMemberRaw-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
Parse-10 9.000 ± 0% 9.000 ± 0% ~ (p=1.000 n=10) ¹
String-10 10.000 ± 0% 8.000 ± 0% -20.00% (p=0.000 n=10)
ValueEscape/nothing_to_escape-10 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10 1.000 ± 0% 1.000 ± 0% ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10 2.000 ± 0% 2.000 ± 0% ~ (p=1.000 n=10) ¹
MemberString-10 4.000 ± 0% 4.000 ± 0% ~ (p=1.000 n=10) ¹
geomean ² -2.75% ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```
FYI, the old implementation of `NewMemberRaw` didn't verify the value,
so the benchmark result of `NewMemberRaw` is not an apple-to-apple
comparison of `utf8.ValidString` and `validateKey`.
---------
Co-authored-by: Chester Cheung <cheung.zhy.csu@gmail.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2024-08-15 16:50:34 -07:00
Kevin Burke
aba4ccb5a0
baggage: fix grammar error ( #5634 )
2024-07-22 09:15:27 +02:00
Santi Leira
7e0af515e2
baggage: Fix invalid percent-encoded octet sequences ( #5528 )
...
# Goal
Replace the percent encoded octet sequence with the replacement code
point (U+FFFD) when it doesn't match the UTF-8 encoding schema.
Issue: https://github.com/open-telemetry/opentelemetry-go/issues/5519
Current behavior:
```
package main
import (
"fmt"
"log"
"unicode/utf8"
"go.opentelemetry.io/otel/baggage"
)
func main() {
kv := "k=aa%ffcc"
b, err := baggage.Parse(kv)
if err != nil {
log.Fatal(err)
}
val := b.Members()[0].Value()
fmt.Println(len(val)) # 5
fmt.Println(utf8.ValidString(val)) # false
}
```
Expected behavior:
```
package main
import (
"fmt"
"log"
"unicode/utf8"
"go.opentelemetry.io/otel/baggage"
)
func main() {
kv := "k=aa%ffcc"
b, err := baggage.Parse(kv)
if err != nil {
log.Fatal(err)
}
val := b.Members()[0].Value()
fmt.Println(len(val)) # 7
fmt.Println(utf8.ValidString(val)) # true
}
```
## Benchmark
- `go test -bench=BenchmarkParse -count 20 > old.txt`
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
BenchmarkParse-10 1548118 774.3 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1547653 786.0 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1544949 770.5 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1558972 770.2 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1554973 774.7 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1550200 779.6 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1545100 774.3 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1549634 777.5 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1552530 769.6 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1536499 855.0 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1552244 770.4 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1560225 767.4 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1562738 772.3 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1556679 838.9 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1562500 777.1 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1530901 836.5 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1000000 1372 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1534678 780.3 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1366180 822.4 ns/op 864 B/op 8 allocs/op
BenchmarkParse-10 1539852 796.8 ns/op 864 B/op 8 allocs/op
PASS
ok go.opentelemetry.io/otel/baggage 40.839s
```
- `go test -bench=BenchmarkParse -count 20 > new.txt`
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
BenchmarkParse-10 1355893 886.6 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1349192 883.1 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1363053 880.4 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1372404 875.7 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1359979 880.7 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1360497 874.7 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1375520 870.2 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1375268 882.8 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1361998 964.8 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1373461 961.5 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1378065 872.6 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1377290 879.0 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1362094 885.6 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1352175 915.9 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1364914 887.9 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1355782 890.5 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1361848 1245 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1163396 878.8 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1370886 916.6 ns/op 888 B/op 9 allocs/op
BenchmarkParse-10 1340149 1175 ns/op 888 B/op 9 allocs/op
PASS
ok go.opentelemetry.io/otel/baggage 44.347s
```
- `benchstat old.txt new.txt`
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
Parse-10 777.3n ± 3% 884.4n ± 4% +13.77% (p=0.000 n=20)
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
Parse-10 864.0 ± 0% 888.0 ± 0% +2.78% (p=0.000 n=20)
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
Parse-10 8.000 ± 0% 9.000 ± 0% +12.50% (p=0.000 n=20)
```
---------
Co-authored-by: Damien Mathieu <42@dmathieu.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2024-07-08 15:01:04 +02:00
Damien Mathieu
6d45f283c7
Add errorlint linter ( #5535 )
...
This is the last PR adding missing linters, adding
[errorlint](https://github.com/polyfloyd/go-errorlint ).
Co-authored-by: Sam Xie <sam@samxie.me>
2024-06-25 10:55:00 -07:00
Fabio Bozzo
478f85bb15
fix(baggage): validate chars panic with 0x80 ( #5494 )
...
The validation rule for baggage key/values chars has a N+1 problem with
the unicode value: `0x80`.
For instance, `baggage.NewMemberRaw` could be called with a string value
including the rune `128` and return no error.
Then `baggage.New` would panic on `validateValueChar`:
```
=== RUN TestValidateValueChar
--- FAIL: TestValidateValueChar (0.00s)
panic: runtime error: index out of range [128] with length 128 [recovered]
panic: runtime error: index out of range [128] with length 128
```
---------
Co-authored-by: Sam Xie <sam@samxie.me>
2024-06-17 09:03:57 -07:00
Moises Vega
0fc35e0e93
feat: opt for concatenation instead of using fmt.Sprintf ( #5286 )
...
* feat: opt for concatenation instead of using fmt.Sprintf
* Update Changelog
---------
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Damien Mathieu <damien.mathieu@elastic.co>
2024-05-07 07:19:08 -07:00
Kevin Burke
906c4909fa
baggage: more efficient member validation ( #5214 )
2024-04-19 08:45:54 +02:00
Alex Boten
e055c7d315
[chore] fix typo in baggage.NewMember docs ( #5231 )
...
Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com>
2024-04-18 23:09:51 +02:00
Sam Xie
2f73208044
Fix spelling errors in baggage.go ( #5120 )
...
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2024-04-01 09:35:55 -07:00
Damien Mathieu
edb788bf49
Add READMEs to every package ( #5103 )
2024-03-26 20:13:54 +01:00
Tyler Yahn
a7034da631
Use slices instead of sort pkg ( #4992 )
...
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2024-02-29 13:03:36 -08:00
Robert Pająk
7dea232a46
[chore] Simplify the license header ( #4987 )
2024-02-29 07:05:28 +01:00
Robert Pająk
259143a662
baggage: Add NewMemberRaw and NewKeyValuePropertyRaw ( #4804 )
2024-01-10 14:02:57 +01:00
Robert Pająk
08b856faeb
baggage: Member.String encodes only when necessary ( #4775 )
2023-12-28 18:21:44 +01:00
Robert Pająk
885210bf33
baggage: Fix escaping in Member.String ( #4756 )
...
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2023-12-21 09:16:13 +01:00
Robert Pająk
43bd47de6e
baggage: Fix Parse to validate member value before percent-decoding ( #4755 )
2023-12-19 14:38:58 +01:00
Cristian Velazquez
057f897096
baggage: Improve performance ( #4743 )
2023-12-14 16:48:28 +01:00
Nathan J Mehl
bdb9322ebd
Use url.PathUnescape rather than url.QueryUnescape in baggage parsing ( #4667 )
...
* Use url.PathUnescape rather than url.QueryUnescape
I believe this addresses the majority of the cases described in
https://github.com/open-telemetry/opentelemetry-go/issues/3601
Golang's url.QueryUnescape will render url _path_ elements (e.g. /, +)
as spaces: `foo+bar` is rendered as `foo bar`. Path elements are (as I
read the spec) legal W3C baggage values, and replacing them with spaces
fails the value validation regex.
url.PathEscape allows path elements through unmolested.
Signed-off-by: Nathan J. Mehl <n@oden.io>
* Update CHANGELOG.md
address comments
Co-authored-by: Robert Pająk <pellared@hotmail.com>
---------
Signed-off-by: Nathan J. Mehl <n@oden.io>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2023-10-31 15:02:17 -07:00
Yuri Shkuro
14b3a985f5
[baggage] Remove unused private field ( #4318 )
...
Signed-off-by: Yuri Shkuro <github@ysh.us>
2023-08-15 09:48:44 -05:00
Mikhail Mazurskiy
f95bee22b9
Use strings.Cut() instead of string.SplitN() ( #4049 )
...
strings.Cut() generates less garbage as it does not allocate the slice to hold parts.
2023-05-17 09:28:44 -07:00
ReStartercc
0963f59955
Fix baggage.NewMember to decode the accepted value ( #3226 )
...
* Fix baggage.NewMember to decode the accepted value
`value` is decoded and stored after validating the input parameters.
Corresponding test cases are modified so that we can make sure `value` is properly encoded before creating Member.
* fix md lint
* add function document to NewMember for value encoding and decoding
* remove redundant comments and fix CHANGELOG.md
* fix wrong PR number in the changelog
* fix wrong PR number
* fix md-lint
Co-authored-by: Chester Cheung <cheung.zhy.csu@gmail.com>
2022-10-18 12:45:04 -07:00
Chester Cheung
30fcf786c3
bugfix: fix baggage set member failed ( #3165 )
...
* fix baggage set member failed
* add unittest
* fix unittest
* rewrite unittest code
2022-09-17 12:54:12 -07:00
Petrie Liu
c2dc940e0b
fix typo ( #2986 )
...
* fix typo
* spell fix
2022-07-02 08:55:14 -07:00
Tyler Yahn
1f5b159161
Use already enabled revive linter and add depguard ( #2883 )
...
* Refactor golangci-lint conf
Order settings alphabetically.
* Add revive settings to golangci conf
* Check blank imports
* Check bool-literal-in-expr
* Check constant-logical-expr
* Check context-as-argument
* Check context-key-type
* Check deep-exit
* Check defer
* Check dot-imports
* Check duplicated-imports
* Check early-return
* Check empty-block
* Check empty-lines
* Check error-naming
* Check error-return
* Check error-strings
* Check errorf
* Stop ignoring context first arg in tests
* Check exported comments
* Check flag-parameter
* Check identical branches
* Check if-return
* Check increment-decrement
* Check indent-error-flow
* Check deny list of go imports
* Check import shadowing
* Check package comments
* Check range
* Check range val in closure
* Check range val address
* Check redefines builtin id
* Check string-format
* Check struct tag
* Check superfluous else
* Check time equal
* Check var naming
* Check var declaration
* Check unconditional recursion
* Check unexported return
* Check unhandled errors
* Check unnecessary stmt
* Check unnecessary break
* Check waitgroup by value
* Exclude deep-exit check in example*_test.go files
2022-05-19 15:15:07 -05:00
Damien Mathieu
cb76cf1b0d
Validate members once, in NewMember
( #2522 )
...
* use NewMember, or specify if the member is not validated when creating new ones
* expect members to already be validated when creating a new package
* add changelog entry
* add an isEmpty field to member and property for quick validation
* rename isEmpty to hasData
So by default, an empty struct really is marked as having no data
* Update baggage/baggage_test.go
Co-authored-by: Aaron Clawson <Aaron.Clawson@gmail.com>
* don't validate the member in parseMember, we alredy ran that validation
We also don't want to use NewMember, as that runs the property
validation again, making the benchmark quite slower
* move changelog entry to the fixed section
* provide the member/property data when returning an invalid error
Co-authored-by: Aaron Clawson <Aaron.Clawson@gmail.com>
2022-02-04 08:19:39 -08:00
Aaron Clawson
5f41868675
Un-escape url coding when parsing baggage. ( #2529 )
...
* un-escape url coding when parsing baggage.
* Added changelog
Co-authored-by: Aaron Clawson <MadVikingGod@users.noreply.github.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2022-01-24 09:17:45 -08:00
José Carlos Chávez
099df58e4e
chore: adds vanity import check. ( #2255 )
...
* chore: adds vanity import check.
* chore: runs vanity import check on ci.
* fix: set right target on CI.
* fix: fixes install for porto.
* fix: install right proto bin.
* chore: list all files insides the tools directory.
* fix: fixes vanity import target
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* chore(vanity-imports): adds vanity import support.
* fix: fixes internal generation.
* chore: runs go mod tidy in tools.
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
2021-09-27 22:37:26 -04:00
Tyler Yahn
92551d3933
Prerelease v1.0.0 ( #2250 )
...
* Update versions file for 1.0.0 release
* Prepare stable-v1 for version v1.0.0
* Update trace signal status in documentation
* Update changelog
* Update CHANGELOG.md
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Robert Pająk <pellared@hotmail.com>
2021-09-20 13:02:46 -07:00
Anthony Mirabella
ced177b795
Pre-release 1.0.0-RC1 ( #2013 )
...
* Add versions.yaml to specify module version sets
* Prepare for releasing v1.0.0-RC1
* Update experimental-metrics and bridge module sets to v0.21.0
* Prepare for releasing v0.21.0
* Fixup go.mod version references
* Update version.go
* Update CHANGELOG
* Update godoc references to "pre-GA phase" for RC1 packages
* Update website_docs for 1.0.0-RC1
Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com>
2021-06-18 11:22:16 -04:00
Anderson Queiroz
7a0cee7b3a
Replaces golint by revive and fix newly reported linter issues ( #1946 )
...
* replaces golint by revive and fix newly reported linter issues
* add pull request ID to CHANGELOG.md
* Update internal/matchers/temporal_matcher.go
Co-authored-by: Robert Pająk <pellared@hotmail.com>
* fix pull request issues
* explains why the linter is disabled
* Update semconv/http.go
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* Update metric/unit/unit.go
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* restores 'example/passthrough/go.sum' to original state
* fix after rebase
* export ErrInvalidAsyncRunner again and add nolint
* Update trace/tracestate.go
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* Update sdk/metric/sdk.go
Co-authored-by: Aaron Clawson <Aaron.Clawson@gmail.com>
* Fix ContextWithoutBaggage comment
* Fix SpanEndOption comment
Co-authored-by: Robert Pająk <pellared@hotmail.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Aaron Clawson <Aaron.Clawson@gmail.com>
Co-authored-by: Tyler Yahn <codingalias@gmail.com>
2021-06-08 10:10:01 -07:00
Tyler Yahn
4bf6150fa9
Add baggage implementation based on the W3C and OpenTelemetry specification ( #1967 )
...
* Rename baggage context file
* Initial baggage implementation
* Initial tests
* More tests
* Update baggage context functionality
* Add New method to baggage pkg
* Update namedtracer example
* URL encode baggage values
* Refactor and use internal baggage pkg
* Update OpenTracing bridge
* Update baggage propagator
* Fix lint and test errors
* Add changes to changelog
* Apply suggestions from code review
* Rename testcase field per suggestion
* Update test to verify last-one-wins semantics
* Explicitly seed random numbers with static seed in tests
* Parse Member key/value with string split
* Add test for member parse with equal signs in value
* Trim whitespaces for member key/value
2021-06-08 08:06:37 -07:00
Punya Biswal
ecf65d7968
Rename otel/label -> otel/attribute ( #1541 )
...
* Rename otel/label -> otel/attr
Leave the imported name alone, to avoid a large diff and conflicts
* Better import comment
* Update CHANGELOG.md
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
* otel/attr -> otel/attribute
* Missed the changelog entry
* Get rid of import renaming
* Merge remaining conflicts
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Anthony Mirabella <a9@aneurysm9.com>
2021-02-18 12:59:37 -05:00
Krzesimir Nowak
7022c12bfc
Update the package docs for the new API layout ( #1346 )
2020-11-17 10:30:22 -05:00
Krzesimir Nowak
63a11144cf
Move baggage and propagation to separate packages ( #1325 )
...
* Move propagation code to propagation package
* Move baggage code to baggage package
* Update changelog
* Make docs of baggage.Set more clear
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2020-11-13 07:34:24 -08:00