diff options
| author | Shulhan <ms@kilabit.info> | 2022-01-10 00:02:29 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2022-01-10 00:02:29 +0700 |
| commit | 1e73389d6444fe5216f06cfdfb3b5b614add3481 (patch) | |
| tree | 0af7ee260d2cc2841810a365d86b3818e609846a | |
| parent | 351589137091f5831034ccecd2f6772ff3b78cf8 (diff) | |
| download | pakakeh.go-1e73389d6444fe5216f06cfdfb3b5b614add3481.tar.xz | |
Release share v0.33.0 (2022-01-09)v0.33.0
Happy New Year!
Three years has passed since the first release of this multi-libraries (or Go
module), and we have released at least 33 new features with several bugs here
and there.
For anyone who use this module, I hope it help you, as the module name
intended "share", and sorry if its too many breaking changes.
Live long and prosper!
See you again next year.
| -rw-r--r-- | CHANGELOG.adoc | 182 | ||||
| -rw-r--r-- | _doc/CHANGELOG.html | 2876 | ||||
| -rw-r--r-- | share.go | 2 |
3 files changed, 2901 insertions, 159 deletions
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 2a1056ce..0868c023 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -3,6 +3,188 @@ This library is released every month, usually at the first week of month. +== share v0.33.0 (2022-01-09) + +Happy New Year! + +Three years has passed since the first release of this multi-libraries (or Go +module), and we have released at least 33 new features with several bugs here +and there. + +For anyone who use this module, I hope it help you, as the module name +intended "share", and sorry if its too many breaking changes. + +Live long and prosper! +See you again next year. + +=== New features + +* cmd/gofilemode: new command to decode the Go file mode ++ +The Go has their own file mode that works across all operating system. +The file mode is represented by uint64, the command line will convert it +to fs.FileMode and print each possible flag on it including the +permission. + +* lib/sql: make the TruncateTable run with cascade and restart identity ++ +-- +On table that contains foreign key, truncate without cascade may cause +the method fail. + +Also, since TruncateTable is, and should be only, used on testing, any +identity columns, for example serial, should be reset back to its initial +value. On PostgreSQL this means the truncate table is with +"RESTART IDENTITY". +-- + +* cmd/epoch: command line to print and parse Unix timestamp ++ +-- +Program epoch print the current time (Unix seconds, milliseconds, +nanoseconds, local time, and UTC time) or the time based on the epoch on +first parameter. +Usage, + + epoch <unix-seconds|unix-milliseconds|unix-nanoseconds> + +Without a parameter, it will print the current time. +With single parameter, it will print the time based on that epoch. +-- + +=== Breaking changes + +* lib/http: refactoring NewClient to accept single struct ++ +-- +Previously, the NewClient function accept three parameters: serverURL, +http.Header, and insecure. If we want to add another parameter, +for example timeout it will cause changes on the function signature. + +To prevent this changes in the future, we change it now. The NewClient +now accept single struct. + +While at it, we add option to set Timeout. + +The Timeout affect the http Transport Timeout and TLSHandshakeTimeout. +The field is optional, if not set it will set to 10 seconds. +-- + +* lib/http: remove field memfs.Options in ServerOptions ++ +This options is duplicate with Memfs.Opts. + +* lib/websocket: add "ok" return value on ClientManager Context ++ +The ok return value will be true if the context exist or false otherwise. + +* lib/memfs: remove field ContentEncoding from EmbedOptions and Node ++ +-- +The original idea for option ContentEncoding in EmbedOptions and Node +is to save spaces, compressing the content on disk on embedding and +doing transport, when the MemFS instance is used to serve the (embedded) +contents of file system. + +This option turns out break the HTTP content negotiation [1] of +accept-encoding header, if the HTTP server does not handle it properly, +which default Go HTTP server does not. + +In order to prevent this issue in the future, for anyone who use the +memfs for serving static HTTP contents, we remove the options and store +the embedded content as is and let the HTTP server handle how the +compression by itself. +-- + +* lib/email: refacforing ParseMailbox ++ +This commit changes the signature of ParseMailbox by returning no error. + +[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation + +=== Bug fixes + +* lib/memfs: skip mount if the Root node has been initialized + +* lib/websocket: fix race conditition on handleText ++ +Instead of accessing the ctx field directly, call the Context() method +to prevent data race. + +* lib/sql: check for EOF on loadSQL ++ +-- +There is probably a regression in Go that cause ioutil.ReadAll return +io.EOF, while it should not, because the documentation said that + + A successful call returns err == nil, not err == EOF. + +But in this, using http.FileSystem, the ioutil.ReadAll now return EOF +and we need to check it to make the migration can run without an error. +-- + +=== Enhancements + +* lib/io: realign all structs ++ +-- +The struct realign, save the occupied of struct size in the memory, + +* DirWatcher: from 184 to 144 bytes (-40 bytes) +* Reader: from 16 to 8 bytes (-8 bytes) +* Watcher: from 32 to 24 bytes (-8 bytes) +-- + +* lib/http: realign all structs ++ +-- +Changes, +* Client: from 56 to 48 bytes (-8 bytes) +* CORSOptions: from 104 to 88 bytes (-16 bytes) +* Endpoint: from 64 to 32 bytes (-32 bytes) +* EndpointRequest: from 72 to 56 bytes (-16 bytes) +* route: from 56 to 32 bytes (-24 bytes) + +Other changes is struct on unit tests. +-- + +* lib/memfs: add method Init ++ +The Init provided to initialize MemFS instance if its Options is set +directly, not through New() function. + +* lib/memfs: embed the Embed options and GenFuncName ++ +This is to make the instance of memfs initialize from init is reusable. + +* lib/memfs: realign struct Node, Options, PathNode, and on unit tests ++ +-- +The realign save storage spaces on struct, + +* Node: from 240 to 224 bytes (-16 bytes) +* Options: from 112 to 104 bytes (-8 bytes) +* PathNode: from 16 to 8 bytes (-8 bytes) +-- + +* lib/email: realign the struct Mailbox ++ +This changes the storage size from 80 to 72 bytes (-8 bytes). + +=== Chores + +* github/workflows: remove step to get dependencies ++ +The Go module should handle the dependencies automatically. + +* github/workflows: set go version to 1.17.6 + +* lib/email: convert the unit test for ParseMailbox to examples ++ +Since the ParseMailbox is public we can provide an examples and test +at the same times. + + == share v0.32.0 (2021-12-03) This release bring major changes and enhancements to package dns and math/big. diff --git a/_doc/CHANGELOG.html b/_doc/CHANGELOG.html index d8fe8dd8..23838706 100644 --- a/_doc/CHANGELOG.html +++ b/_doc/CHANGELOG.html @@ -187,7 +187,7 @@ dd { margin: 2.5rem 0; } -/** Custom classes for asciidoc */ +/** Custom classes */ #toctitle { display: none; } @@ -234,203 +234,284 @@ dd { <div id="toc" class="toc"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> -<li><a href="#_share_v0_24_0_2021_03_xx">share v0.24.0 (2021-03-xx)</a> +<li><a href="#_share_v0_33_0_2022_01_09">share v0.33.0 (2022-01-09)</a> <ul class="sectlevel2"> -<li><a href="#_breaking_changes">Breaking changes</a></li> <li><a href="#_new_features">New features</a></li> +<li><a href="#_breaking_changes">Breaking changes</a></li> +<li><a href="#_bug_fixes">Bug fixes</a></li> +<li><a href="#_enhancements">Enhancements</a></li> +<li><a href="#_chores">Chores</a></li> </ul> </li> -<li><a href="#_share_v0_23_0_2021_02_05">share v0.23.0 (2021-02-05)</a> +<li><a href="#_share_v0_32_0_2021_12_03">share v0.32.0 (2021-12-03)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_1">Breaking changes</a></li> <li><a href="#_new_features_1">New features</a></li> -<li><a href="#_enhancements">Enhancements</a></li> -<li><a href="#_bug_fixes">Bug fixes</a></li> +<li><a href="#_bug_fixes_1">Bug fixes</a></li> +<li><a href="#_enhancements_1">Enhancements</a></li> </ul> </li> -<li><a href="#_share_v0_22_0_2021_01_06">share v0.22.0 (2021-01-06)</a> +<li><a href="#_share_v0_31_0_2021_11_04">share v0.31.0 (2021-11-04)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_2">Breaking changes</a></li> <li><a href="#_new_features_2">New features</a></li> -<li><a href="#_enhancements_1">Enhancements</a></li> +<li><a href="#_bug_fixes_2">Bug fixes</a></li> +<li><a href="#_chores_1">Chores</a></li> </ul> </li> -<li><a href="#_share_v0_21_0_2020_12_06">share v0.21.0 (2020-12-06)</a> +<li><a href="#_share_v0_30_0_2021_10_04">share v0.30.0 (2021-10-04)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_3">Breaking changes</a></li> <li><a href="#_new_features_3">New features</a></li> -<li><a href="#_bug_fixes_1">Bug fixes</a></li> +<li><a href="#_bug_fixes_3">Bug fixes</a></li> <li><a href="#_enhancements_2">Enhancements</a></li> -<li><a href="#_chores">Chores</a></li> +<li><a href="#_chores_2">Chores</a></li> </ul> </li> -<li><a href="#_share_v0_20_1_2020_11_08">share v0.20.1 (2020-11-08)</a> +<li><a href="#_share_v0_29_2_2021_09_06">share v0.29.2 (2021-09-06)</a> <ul class="sectlevel2"> -<li><a href="#_bug_fixes_2">Bug fixes</a></li> +<li><a href="#_bug_fixes_4">Bug fixes</a></li> <li><a href="#_enhancements_3">Enhancements</a></li> -<li><a href="#_chores_1">Chores</a></li> +<li><a href="#_chores_3">Chores</a></li> </ul> </li> -<li><a href="#_share_v0_20_0_2020_10_05">share v0.20.0 (2020-10-05)</a> -<ul class="sectlevel2"> -<li><a href="#_new_features_4">New features</a></li> -<li><a href="#_enhancements_4">Enhancements</a></li> -</ul> -</li> -<li><a href="#_share_v0_19_0_2020_09_08">share v0.19.0 (2020-09-08)</a> +<li><a href="#_share_v0_29_1_2021_08_06">share v0.29.1 (2021-08-06)</a></li> +<li><a href="#_share_v0_29_0_2021_08_06">share v0.29.0 (2021-08-06)</a> <ul class="sectlevel2"> +<li><a href="#_new_feature">New feature</a></li> <li><a href="#_breaking_changes_4">Breaking changes</a></li> -<li><a href="#_new_features_5">New features</a></li> -<li><a href="#_bug_fixes_3">Bug fixes</a></li> +<li><a href="#_enhancements_4">Enhancements</a></li> +<li><a href="#_bug_fix">Bug fix</a></li> </ul> </li> -<li><a href="#_share_v0_18_0_2020_08_06">share v0.18.0 (2020-08-06)</a> +<li><a href="#_share_v0_28_0_2021_07_06">share v0.28.0 (2021-07-06)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_5">Breaking changes</a></li> -<li><a href="#_bug_fixes_4">Bug fixes</a></li> <li><a href="#_enhancements_5">Enhancements</a></li> </ul> </li> -<li><a href="#_share_v0_17_0_2020_07_05">share v0.17.0 (2020-07-05)</a> +<li><a href="#_share_v0_27_0_2021_06_05">share v0.27.0 (2021-06-05)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_6">Breaking changes</a></li> -<li><a href="#_bug_fixes_5">Bug fixes</a></li> +<li><a href="#_new_features_4">New features</a></li> <li><a href="#_enhancements_6">Enhancements</a></li> +<li><a href="#_bug_fixes_5">Bug fixes</a></li> </ul> </li> -<li><a href="#_share_v0_16_0_2020_06_05">share v0.16.0 (2020-06-05)</a> +<li><a href="#_share_v0_26_0_2021_05_03">share v0.26.0 (2021-05-03)</a> +<ul class="sectlevel2"> +<li><a href="#_new_features_5">New features</a></li> +<li><a href="#_enhancements_7">Enhancements</a></li> +<li><a href="#_chores_4">Chores</a></li> +</ul> +</li> +<li><a href="#_share_v0_25_1_2021_04_06">share v0.25.1 (2021-04-06)</a></li> +<li><a href="#_share_v0_25_0_2021_04_06">share v0.25.0 (2021-04-06)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_7">Breaking changes</a></li> -<li><a href="#_bug_fixes_6">Bug fixes</a></li> <li><a href="#_new_features_6">New features</a></li> -<li><a href="#_enhancements_7">Enhancements</a></li> +<li><a href="#_enhancements_8">Enhancements</a></li> </ul> </li> -<li><a href="#_share_v0_15_0_2020_05_04">share v0.15.0 (2020-05-04)</a> +<li><a href="#_share_v0_24_0_2021_03_06">share v0.24.0 (2021-03-06)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_8">Breaking changes</a></li> <li><a href="#_new_features_7">New features</a></li> -<li><a href="#_enhancements_8">Enhancements</a></li> -<li><a href="#_bug_fixes_7">Bug fixes</a></li> +<li><a href="#_enhancements_9">Enhancements</a></li> +<li><a href="#_bug_fixes_6">Bug fixes</a></li> </ul> </li> -<li><a href="#_share_v0_14_0_2020_04_03">share v0.14.0 (2020-04-03)</a> +<li><a href="#_share_v0_23_0_2021_02_05">share v0.23.0 (2021-02-05)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_9">Breaking changes</a></li> <li><a href="#_new_features_8">New features</a></li> -<li><a href="#_enhancements_9">Enhancements</a></li> -<li><a href="#_bug_fixes_8">Bug fixes</a></li> +<li><a href="#_enhancements_10">Enhancements</a></li> +<li><a href="#_bug_fixes_7">Bug fixes</a></li> </ul> </li> -<li><a href="#_share_v0_13_0_2020_03_11">share v0.13.0 (2020-03-11)</a> +<li><a href="#_share_v0_22_0_2021_01_06">share v0.22.0 (2021-01-06)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_10">Breaking changes</a></li> <li><a href="#_new_features_9">New features</a></li> -<li><a href="#_enhancements_10">Enhancements</a></li> -<li><a href="#_bug_fixes_9">Bug Fixes</a></li> +<li><a href="#_enhancements_11">Enhancements</a></li> </ul> </li> -<li><a href="#_share_v0_12_0_2020_02_13">share v0.12.0 (2020-02-13)</a> +<li><a href="#_share_v0_21_0_2020_12_06">share v0.21.0 (2020-12-06)</a> <ul class="sectlevel2"> <li><a href="#_breaking_changes_11">Breaking changes</a></li> <li><a href="#_new_features_10">New features</a></li> -<li><a href="#_enhancements_11">Enhancements</a></li> -<li><a href="#_bug_fixes_10">Bug fixes</a></li> +<li><a href="#_bug_fixes_8">Bug fixes</a></li> +<li><a href="#_enhancements_12">Enhancements</a></li> +<li><a href="#_chores_5">Chores</a></li> </ul> </li> -<li><a href="#_share_v0_11_0_2019_12_26">share v0.11.0 (2019-12-26)</a> +<li><a href="#_share_v0_20_1_2020_11_08">share v0.20.1 (2020-11-08)</a> +<ul class="sectlevel2"> +<li><a href="#_bug_fixes_9">Bug fixes</a></li> +<li><a href="#_enhancements_13">Enhancements</a></li> +<li><a href="#_chores_6">Chores</a></li> +</ul> +</li> +<li><a href="#_share_v0_20_0_2020_10_05">share v0.20.0 (2020-10-05)</a> <ul class="sectlevel2"> -<li><a href="#_breaking_changes_12">Breaking changes</a></li> <li><a href="#_new_features_11">New features</a></li> -<li><a href="#_enhancements_12">Enhancements</a></li> +<li><a href="#_enhancements_14">Enhancements</a></li> +</ul> +</li> +<li><a href="#_share_v0_19_0_2020_09_08">share v0.19.0 (2020-09-08)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_12">Breaking changes</a></li> +<li><a href="#_new_features_12">New features</a></li> +<li><a href="#_bug_fixes_10">Bug fixes</a></li> +</ul> +</li> +<li><a href="#_share_v0_18_0_2020_08_06">share v0.18.0 (2020-08-06)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_13">Breaking changes</a></li> <li><a href="#_bug_fixes_11">Bug fixes</a></li> +<li><a href="#_enhancements_15">Enhancements</a></li> +</ul> +</li> +<li><a href="#_share_v0_17_0_2020_07_05">share v0.17.0 (2020-07-05)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_14">Breaking changes</a></li> +<li><a href="#_bug_fixes_12">Bug fixes</a></li> +<li><a href="#_enhancements_16">Enhancements</a></li> +</ul> +</li> +<li><a href="#_share_v0_16_0_2020_06_05">share v0.16.0 (2020-06-05)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_15">Breaking changes</a></li> +<li><a href="#_bug_fixes_13">Bug fixes</a></li> +<li><a href="#_new_features_13">New features</a></li> +<li><a href="#_enhancements_17">Enhancements</a></li> +</ul> +</li> +<li><a href="#_share_v0_15_0_2020_05_04">share v0.15.0 (2020-05-04)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_16">Breaking changes</a></li> +<li><a href="#_new_features_14">New features</a></li> +<li><a href="#_enhancements_18">Enhancements</a></li> +<li><a href="#_bug_fixes_14">Bug fixes</a></li> +</ul> +</li> +<li><a href="#_share_v0_14_0_2020_04_03">share v0.14.0 (2020-04-03)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_17">Breaking changes</a></li> +<li><a href="#_new_features_15">New features</a></li> +<li><a href="#_enhancements_19">Enhancements</a></li> +<li><a href="#_bug_fixes_15">Bug fixes</a></li> +</ul> +</li> +<li><a href="#_share_v0_13_0_2020_03_11">share v0.13.0 (2020-03-11)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_18">Breaking changes</a></li> +<li><a href="#_new_features_16">New features</a></li> +<li><a href="#_enhancements_20">Enhancements</a></li> +<li><a href="#_bug_fixes_16">Bug Fixes</a></li> +</ul> +</li> +<li><a href="#_share_v0_12_0_2020_02_13">share v0.12.0 (2020-02-13)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_19">Breaking changes</a></li> +<li><a href="#_new_features_17">New features</a></li> +<li><a href="#_enhancements_21">Enhancements</a></li> +<li><a href="#_bug_fixes_17">Bug fixes</a></li> +</ul> +</li> +<li><a href="#_share_v0_11_0_2019_12_26">share v0.11.0 (2019-12-26)</a> +<ul class="sectlevel2"> +<li><a href="#_breaking_changes_20">Breaking changes</a></li> +<li><a href="#_new_features_18">New features</a></li> +<li><a href="#_enhancements_22">Enhancements</a></li> +<li><a href="#_bug_fixes_18">Bug fixes</a></li> </ul> </li> <li><a href="#_share_v0_10_2_2019_12_07">share v0.10.2 (2019-12-07)</a> <ul class="sectlevel2"> -<li><a href="#_bug_fixes_12">Bug Fixes</a></li> +<li><a href="#_bug_fixes_19">Bug Fixes</a></li> </ul> </li> <li><a href="#_share_v0_10_1_2019_12_05">share v0.10.1 (2019-12-05)</a> <ul class="sectlevel2"> -<li><a href="#_bug_fixes_13">Bug Fixes</a></li> -<li><a href="#_enhancements_13">Enhancements</a></li> +<li><a href="#_bug_fixes_20">Bug Fixes</a></li> +<li><a href="#_enhancements_23">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_10_0_2019_11_05">share v0.10.0 (2019-11-05)</a> <ul class="sectlevel2"> -<li><a href="#_new_features_12">New Features</a></li> -<li><a href="#_breaking_changes_13">Breaking Changes</a></li> -<li><a href="#_enhancements_14">Enhancements</a></li> -<li><a href="#_bug_fixes_14">Bug Fixes</a></li> +<li><a href="#_new_features_19">New Features</a></li> +<li><a href="#_breaking_changes_21">Breaking Changes</a></li> +<li><a href="#_enhancements_24">Enhancements</a></li> +<li><a href="#_bug_fixes_21">Bug Fixes</a></li> </ul> </li> <li><a href="#_share_v0_9_0_2019_10_08">share v0.9.0 (2019-10-08)</a> <ul class="sectlevel2"> -<li><a href="#_new_features_13">New Features</a></li> -<li><a href="#_breaking_changes_14">Breaking Changes</a></li> -<li><a href="#_bug_fixes_15">Bug Fixes</a></li> -<li><a href="#_enhancements_15">Enhancements</a></li> +<li><a href="#_new_features_20">New Features</a></li> +<li><a href="#_breaking_changes_22">Breaking Changes</a></li> +<li><a href="#_bug_fixes_22">Bug Fixes</a></li> +<li><a href="#_enhancements_25">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_8_2_2019_09_05">share v0.8.2 (2019-09-05)</a> <ul class="sectlevel2"> -<li><a href="#_enhancements_16">Enhancements</a></li> +<li><a href="#_enhancements_26">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_8_1_2019_08_05">share v0.8.1 (2019-08-05)</a> <ul class="sectlevel2"> -<li><a href="#_enhancements_17">Enhancements</a></li> +<li><a href="#_enhancements_27">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_8_0_2019_07_09">share v0.8.0 (2019-07-09)</a> <ul class="sectlevel2"> -<li><a href="#_breaking_changes_15">Breaking changes</a></li> -<li><a href="#_new_features_14">New Features</a></li> -<li><a href="#_enhancements_18">Enhancements</a></li> +<li><a href="#_breaking_changes_23">Breaking changes</a></li> +<li><a href="#_new_features_21">New Features</a></li> +<li><a href="#_enhancements_28">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_7_0_2019_06_14">share v0.7.0 (2019-06-14)</a> <ul class="sectlevel2"> -<li><a href="#_breaking_changes_16">Breaking Changes</a></li> -<li><a href="#_new_features_15">New Features</a></li> -<li><a href="#_enhancements_19">Enhancements</a></li> -<li><a href="#_bug_fixes_16">Bug Fixes</a></li> +<li><a href="#_breaking_changes_24">Breaking Changes</a></li> +<li><a href="#_new_features_22">New Features</a></li> +<li><a href="#_enhancements_29">Enhancements</a></li> +<li><a href="#_bug_fixes_23">Bug Fixes</a></li> </ul> </li> <li><a href="#_share_v0_6_1_2019_05_11">share v0.6.1 (2019-05-11)</a></li> <li><a href="#_share_v0_6_0_2019_05_07">share v0.6.0 (2019-05-07)</a> <ul class="sectlevel2"> -<li><a href="#_breaking_changes_17">Breaking Changes</a></li> -<li><a href="#_new_features_16">New Features</a></li> -<li><a href="#_bug_fixes_17">Bug Fixes</a></li> +<li><a href="#_breaking_changes_25">Breaking Changes</a></li> +<li><a href="#_new_features_23">New Features</a></li> +<li><a href="#_bug_fixes_24">Bug Fixes</a></li> <li><a href="#_documentation">Documentation</a></li> </ul> </li> <li><a href="#_share_v0_5_0_2019_04_02">share v0.5.0 (2019-04-02)</a> <ul class="sectlevel2"> -<li><a href="#_new_features_17">New Features</a></li> -<li><a href="#_enhancements_20">Enhancements</a></li> +<li><a href="#_new_features_24">New Features</a></li> +<li><a href="#_enhancements_30">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_4_0_2019_03_01">share v0.4.0 (2019-03-01)</a> <ul class="sectlevel2"> -<li><a href="#_new_features_18">New Features</a></li> -<li><a href="#_enhancements_21">Enhancements</a></li> +<li><a href="#_new_features_25">New Features</a></li> +<li><a href="#_enhancements_31">Enhancements</a></li> <li><a href="#_fixes">Fixes</a></li> </ul> </li> <li><a href="#_share_v0_3_0_2019_02_01">share v0.3.0 (2019-02-01)</a> <ul class="sectlevel2"> <li><a href="#_features_changes">Features Changes</a></li> -<li><a href="#_enhancements_22">Enhancements</a></li> +<li><a href="#_enhancements_32">Enhancements</a></li> <li><a href="#_fixes_1">Fixes</a></li> </ul> </li> <li><a href="#_share_v0_2_0_2019_01_02">share v0.2.0 (2019-01-02)</a> <ul class="sectlevel2"> -<li><a href="#_new_features_19">New Features</a></li> -<li><a href="#_enhancements_23">Enhancements</a></li> +<li><a href="#_new_features_26">New Features</a></li> +<li><a href="#_enhancements_33">Enhancements</a></li> </ul> </li> <li><a href="#_share_v0_1_0_2018_11_29">share v0.1.0 (2018-11-29)</a></li> @@ -447,13 +528,2351 @@ dd { </div> </div> <div class="sect1"> -<h2 id="_share_v0_24_0_2021_03_xx">share v0.24.0 (2021-03-xx)</h2> +<h2 id="_share_v0_33_0_2022_01_09">share v0.33.0 (2022-01-09)</h2> <div class="sectionbody"> +<div class="paragraph"> +<p>Happy New Year!</p> +</div> +<div class="paragraph"> +<p>Three years has passed since the first release of this multi-libraries (or Go +module), and we have released at least 33 new features with several bugs here +and there.</p> +</div> +<div class="paragraph"> +<p>For anyone who use this module, I hope it help you, as the module name +intended "share", and sorry if its too many breaking changes.</p> +</div> +<div class="paragraph"> +<p>Live long and prosper! +See you again next year.</p> +</div> +<div class="sect2"> +<h3 id="_new_features">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>cmd/gofilemode: new command to decode the Go file mode</p> +<div class="paragraph"> +<p>The Go has their own file mode that works across all operating system. +The file mode is represented by uint64, the command line will convert it +to fs.FileMode and print each possible flag on it including the +permission.</p> +</div> +</li> +<li> +<p>lib/sql: make the TruncateTable run with cascade and restart identity</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>On table that contains foreign key, truncate without cascade may cause +the method fail.</p> +</div> +<div class="paragraph"> +<p>Also, since TruncateTable is, and should be only, used on testing, any +identity columns, for example serial, should be reset back to its initial +value. On PostgreSQL this means the truncate table is with +"RESTART IDENTITY".</p> +</div> +</div> +</div> +</li> +<li> +<p>cmd/epoch: command line to print and parse Unix timestamp</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>Program epoch print the current time (Unix seconds, milliseconds, +nanoseconds, local time, and UTC time) or the time based on the epoch on +first parameter. +Usage,</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>epoch <unix-seconds|unix-milliseconds|unix-nanoseconds></pre> +</div> +</div> +<div class="paragraph"> +<p>Without a parameter, it will print the current time. +With single parameter, it will print the time based on that epoch.</p> +</div> +</div> +</div> +</li> +</ul> +</div> +</div> <div class="sect2"> <h3 id="_breaking_changes">Breaking changes</h3> <div class="ulist"> <ul> <li> +<p>lib/http: refactoring NewClient to accept single struct</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>Previously, the NewClient function accept three parameters: serverURL, +http.Header, and insecure. If we want to add another parameter, +for example timeout it will cause changes on the function signature.</p> +</div> +<div class="paragraph"> +<p>To prevent this changes in the future, we change it now. The NewClient +now accept single struct.</p> +</div> +<div class="paragraph"> +<p>While at it, we add option to set Timeout.</p> +</div> +<div class="paragraph"> +<p>The Timeout affect the http Transport Timeout and TLSHandshakeTimeout. +The field is optional, if not set it will set to 10 seconds.</p> +</div> +</div> +</div> +</li> +<li> +<p>lib/http: remove field memfs.Options in ServerOptions</p> +<div class="paragraph"> +<p>This options is duplicate with Memfs.Opts.</p> +</div> +</li> +<li> +<p>lib/websocket: add "ok" return value on ClientManager Context</p> +<div class="paragraph"> +<p>The ok return value will be true if the context exist or false otherwise.</p> +</div> +</li> +<li> +<p>lib/memfs: remove field ContentEncoding from EmbedOptions and Node</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>The original idea for option ContentEncoding in EmbedOptions and Node +is to save spaces, compressing the content on disk on embedding and +doing transport, when the MemFS instance is used to serve the (embedded) +contents of file system.</p> +</div> +<div class="paragraph"> +<p>This option turns out break the HTTP content negotiation [1] of +accept-encoding header, if the HTTP server does not handle it properly, +which default Go HTTP server does not.</p> +</div> +<div class="paragraph"> +<p>In order to prevent this issue in the future, for anyone who use the +memfs for serving static HTTP contents, we remove the options and store +the embedded content as is and let the HTTP server handle how the +compression by itself.</p> +</div> +</div> +</div> +</li> +<li> +<p>lib/email: refacforing ParseMailbox</p> +<div class="paragraph"> +<p>This commit changes the signature of ParseMailbox by returning no error.</p> +</div> +</li> +</ul> +</div> +<div class="paragraph"> +<p>[1] <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation" class="bare">https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation</a></p> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: skip mount if the Root node has been initialized</p> +</li> +<li> +<p>lib/websocket: fix race conditition on handleText</p> +<div class="paragraph"> +<p>Instead of accessing the ctx field directly, call the Context() method +to prevent data race.</p> +</div> +</li> +<li> +<p>lib/sql: check for EOF on loadSQL</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>There is probably a regression in Go that cause ioutil.ReadAll return +io.EOF, while it should not, because the documentation said that</p> +</div> +<div class="literalblock"> +<div class="content"> +<pre>A successful call returns err == nil, not err == EOF.</pre> +</div> +</div> +<div class="paragraph"> +<p>But in this, using http.FileSystem, the ioutil.ReadAll now return EOF +and we need to check it to make the migration can run without an error.</p> +</div> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/io: realign all structs</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>The struct realign, save the occupied of struct size in the memory,</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>DirWatcher: from 184 to 144 bytes (-40 bytes)</p> +</li> +<li> +<p>Reader: from 16 to 8 bytes (-8 bytes)</p> +</li> +<li> +<p>Watcher: from 32 to 24 bytes (-8 bytes)</p> +</li> +</ul> +</div> +</div> +</div> +</li> +<li> +<p>lib/http: realign all structs</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>Changes, +* Client: from 56 to 48 bytes (-8 bytes) +* CORSOptions: from 104 to 88 bytes (-16 bytes) +* Endpoint: from 64 to 32 bytes (-32 bytes) +* EndpointRequest: from 72 to 56 bytes (-16 bytes) +* route: from 56 to 32 bytes (-24 bytes)</p> +</div> +<div class="paragraph"> +<p>Other changes is struct on unit tests.</p> +</div> +</div> +</div> +</li> +<li> +<p>lib/memfs: add method Init</p> +<div class="paragraph"> +<p>The Init provided to initialize MemFS instance if its Options is set +directly, not through New() function.</p> +</div> +</li> +<li> +<p>lib/memfs: embed the Embed options and GenFuncName</p> +<div class="paragraph"> +<p>This is to make the instance of memfs initialize from init is reusable.</p> +</div> +</li> +<li> +<p>lib/memfs: realign struct Node, Options, PathNode, and on unit tests</p> +<div class="openblock"> +<div class="content"> +<div class="paragraph"> +<p>The realign save storage spaces on struct,</p> +</div> +<div class="ulist"> +<ul> +<li> +<p>Node: from 240 to 224 bytes (-16 bytes)</p> +</li> +<li> +<p>Options: from 112 to 104 bytes (-8 bytes)</p> +</li> +<li> +<p>PathNode: from 16 to 8 bytes (-8 bytes)</p> +</li> +</ul> +</div> +</div> +</div> +</li> +<li> +<p>lib/email: realign the struct Mailbox</p> +<div class="paragraph"> +<p>This changes the storage size from 80 to 72 bytes (-8 bytes).</p> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_chores">Chores</h3> +<div class="ulist"> +<ul> +<li> +<p>github/workflows: remove step to get dependencies</p> +<div class="paragraph"> +<p>The Go module should handle the dependencies automatically.</p> +</div> +</li> +<li> +<p>github/workflows: set go version to 1.17.6</p> +</li> +<li> +<p>lib/email: convert the unit test for ParseMailbox to examples</p> +<div class="paragraph"> +<p>Since the ParseMailbox is public we can provide an examples and test +at the same times.</p> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_32_0_2021_12_03">share v0.32.0 (2021-12-03)</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p>This release bring major changes and enhancements to package dns and math/big.</p> +</div> +<div class="sect2"> +<h3 id="_breaking_changes_1">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>math/big: refactoring AddFloat to accept variadic interface{}</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the AddFloat function only accept two interface parameters.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make the AddFloat to accept many interface parameters.</pre> +</div> +</div> +</li> +<li> +<p>math/big: refactor NewFloat to accept interface{} instead of float64 only</p> +<div class="literalblock"> +<div class="content"> +<pre>The following types is added and can be initialized to Float: []byte, +uint, uint16, uint32, uint64, big.Int, *big.Int, big.Rat, and *big.Rat.</pre> +</div> +</div> +</li> +<li> +<p>math/big: refactoring the Rat</p> +<div class="literalblock"> +<div class="content"> +<pre>The promise of this package is to provide the Rat type with RoundToZero +and without panic.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>In order to do that we remove the MustRat() function and check for nil +on pointer receiver before doing operation, and check for zero value +when doing quotation.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Another breaking changes are,</pre> +</div> +</div> +</li> +<li> +<p>Humanize() with nil pointer receiver will return string "0"</p> +</li> +<li> +<p>Any IsXxx() methods with nil pointer receiver will return false</p> +</li> +<li> +<p>MarshalJSON() will nil pointer receiver will return "null" instead of +"0" now</p> +</li> +<li> +<p>lib/dns: refactoring, change signature of client Lookup</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, Lookup() method on Client pass the question name, type, and +class as parameters.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make those parameters into MessageQuestion.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: refactoring ZoneFile into Zone</p> +<div class="literalblock"> +<div class="content"> +<pre>Reason: A Zone is not always represented by file, it just that in this +package, it is.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes rename the type ZoneFile into Zone.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: refactoring message question</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously the type for message question section SectionQuestion.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes, rename the type to MessageQuestion.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: refactoring the section header</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes rename the SectionHeader into MessageHeader.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The pack() method is optimized with the following results,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>benchmark old ns/op new ns/op delta +BenchmarkMessageHeader_pack-8 66.2 21.7 -67.31%</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>benchmark old allocs new allocs delta +BenchmarkMessageHeader_pack-8 3 1 -66.67%</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>benchmark old bytes new bytes delta +BenchmarkMessageHeader_pack-8 32 16 -50.00%</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The unpack() method is simplified by minimizing the if-condition.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes also fix the pack and unpack OpCode for value other then 0, +due to wrong shift value, 2 instead of 3.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: refactoring, introduce new type RecordClass</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the record class is represented by uint16 using prefix +QueryClassXxx.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make the record class to be an independent type, to make +code more strict (prevent passing invalid value), and readable.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: refactoring, create type RecordType to represent type of RR</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we use uint16 to represent type for ResourceRecord Type or +Question type.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>To make the code more strict, where parameter or return value, must be +expected as record type, we add new type to represent the RR type: +RecordType.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes also rename any variable name of QType or qtype to RType +or rtype because QType is misleading. The type defined the +ResourceRecord to be queried not only question.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: remove the fallback name servers (NS) from server options</p> +<div class="literalblock"> +<div class="content"> +<pre>The original idea of fallback NS is to send the query to the one define +to original resolv.conf, instead of using the one defined by user in +ServerOptions NameServers, when an error occured.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>But, most of error usually caused by network (disconnected, time out), +so re-sending query to fallback NS does not have any effect if the network +it self is not working.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes remove the unnecessary and complex fallback NS from +server.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_new_features_1">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/dns: add support to save and load caches to/from storage</p> +<div class="literalblock"> +<div class="content"> +<pre>The CachesSave method write the non-local answers into an io.Writer, +encoded with gob.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The CachesLoad method load the gob encoded answers from an io.Reader.</pre> +</div> +</div> +</li> +<li> +<p>lib/ssh: use agent defined by config or from environment variable</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we only check the environment variable SSH_AUTH_SOCK +to decide whether the client identity will fetched from agent or +from private key file.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes use the GetIdentityAgent from config Section to derive the +path to unix socket. It will return an empty string if the IdentityAgent +is set to "none" in the Section or when SSH_AUTH_SOCK is not exist or +empty.</pre> +</div> +</div> +</li> +<li> +<p>ssh/config: add support for section variable IdentityAgent</p> +<div class="literalblock"> +<div class="content"> +<pre>There are four possible value for IdentityAgent: SSH_AUTH_SOCK, +<$STRING>, <PATH>, or "none". +If SSH_AUTH_SOCK, the socket path is read from the environment variable +SSH_AUTH_SOCK. +If value start with "$", then the socket path is set based on value of +that environment variable. +Other string beside "none" will be considered as path to socket.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes_1">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>math/big: return nil on Quo and QuoRat instead of panic</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, if the first parameter of Quo or the second/next parameters +of QuoRat is not convertable to Rat or zero, the method/function will +panic.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make it less intrusive, instead of panic we check for +zero value and return nil immediately.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: do not cache truncated answer</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously only answer with non-zero response code is ignored.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes ignore also answer where response header is truncated.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_1">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/dns: realign all struct fields</p> +<div class="literalblock"> +<div class="content"> +<pre>Turns out the struct that we frequently used, answer and resource_record, +is not optimized.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>answer.go:15:13: struct with 56 pointer bytes could be 24 = 32 bytes +... +resource_record.go:24:21: struct with 56 pointer bytes could be 40 = 16</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes reorder all structs field to save space in memory.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: make the TCP forwarders as complementary of UDP</p> +<div class="literalblock"> +<div class="content"> +<pre>The TCP forwarders only active when client send the DNS request as TCP. +When the server receive that request it should also forward the request +as TCP not as UDP to prevent the truncated response.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Another use case for TCP is when the response is truncated, the client +will send the query back through TCP connection. The server should +forward this request using TCP instead of UDP.</pre> +</div> +</div> +</li> +<li> +<p>lib/dns: use different packet between UDP and TCP messages</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, all packet size for reading and sending the message is +fixed to 4096, even on UDP.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes set the UDP packet size maximum to 512 bytes and others to +4096 bytes.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, minimize copying packet if its not reusable inside a method.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_31_0_2021_11_04">share v0.31.0 (2021-11-04)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_breaking_changes_2">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: move the embedded parameter to Options</p> +<div class="literalblock"> +<div class="content"> +<pre>Since the GoEmbed can be called only when MemFS instance is initiated, +it would be better if parameters for GoEmbed also initialized in the +struct Options. +In this way any additional parameters needed to add to GoEmbed does not +changes the method signature in the future.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit add new type EmbedOptions that contains the parameters +for GoEmbed.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>In this new type, we add new field EmbedWithoutModTime. +if its true, the modification time for all files and directories are not +stored inside generated code, instead all files will use the current +time when the program is running.</pre> +</div> +</div> +</li> +<li> +<p>lib/totp: make the New to accept only hash with SHA1, SHA256, or SHA512</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the first parameter to New is a function that return +hash.Hash. This signature can be misleading, because md5.New also +can return hash.Hash but not usable in TOTP.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes update the New function signature to accept defined +type that can be set to SHA1, SHA256, or SHA512.</pre> +</div> +</div> +</li> +<li> +<p>lib/bytes: refactoring and cleaning up the bytes package</p> +<div class="literalblock"> +<div class="content"> +<pre>The bytes package, and many other packages in this module, is written +when I still learning and using the Go language for master thesis. +Some of the code, like function signature, does not follow the +Go idiom, at least not how the Go source code looks like.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>A breaking changes,</pre> +</div> +</div> +</li> +<li> +<p>WriteUint16 and WriteUint32 accept slice only without pointer. +There is no need to pass slice as pointer to function if we want +to modify the content, as long as the backing storage is not +changed.</p> +<div class="literalblock"> +<div class="content"> +<pre>Bug fixes,</pre> +</div> +</div> +</li> +<li> +<p>PrintHex: fix print layout on the last line</p> +</li> +<li> +<p>ReadHexByte: fix possible index out of range</p> +</li> +<li> +<p>SkipAfterToken return -1 and false if no token found, as promised +in the comment, instead of the length of text.</p> +<div class="literalblock"> +<div class="content"> +<pre>We move all unit test to example so we have test and example in the +documentation at the same time.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make all test coverage 100%.</pre> +</div> +</div> +</li> +<li> +<p>lib/bytes: refactoring AppendXxx functions</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we pass pointer to slice on AppendInt16, AppendInt32, +AppendUint16, and AppendUint32 functions. This model of function +signature is not a Go idiom. It is written when I am still new to +Go.</pre> +</div> +</div> +</li> +<li> +<p>lib/ascii: change signature of ToLower and ToUpper</p> +<div class="literalblock"> +<div class="content"> +<pre>Using pointer to slice on method or function is not a Go idiom. +It is created when I still new to Go.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: refactoring Node field V into Content</p> +<div class="literalblock"> +<div class="content"> +<pre>The reason why the field named V is because it's short. It's come +from my C/C++ experience that got carried away when writing this +package.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Now, after having more time writing Go, I prefer clarity over +cleverity(?).</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: set the node modification time in embedded file</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes set all node modification time in embedded files to +the node modTime using Unix() and Nanosecond() values.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Since the time will always changes we need to remove the test to +generate file gen_test.go to prevent the file being modified and +re-adding the same file every time we run local tests.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_new_features_2">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/ini: add function IsValidVarName</p> +<div class="literalblock"> +<div class="content"> +<pre>The IsValidVarName check if "v" is valid variable name, where the +first character must be a letter and the rest should contains only +letter, digit, period, hyphen, or underscore. +If "v" is valid it will return true.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: set the node modification time in embedded file</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes set all node modification time in embedded files to +the node modTime using Unix() and Nanosecond() values.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Since the time will always changes we need to remove the test to +generate file gen_test.go to prevent the file being modified and +re-adding the same file every time we run local tests.</pre> +</div> +</div> +</li> +<li> +<p>lib/io: add method String to FileState type</p> +<div class="literalblock"> +<div class="content"> +<pre>The String method return the string representation of FileState. +Usually used only for debugging.</pre> +</div> +</div> +</li> +<li> +<p>lib/smtp: implement method Noop on Client</p> +<div class="literalblock"> +<div class="content"> +<pre>Noop send the NOOP command to server with optional message.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>On success, it will return response with Code 250, StatusOK.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it fix double call to recv on Reset() method.</pre> +</div> +</div> +</li> +<li> +<p>lib/smtp: implement method Reset on Client</p> +<div class="literalblock"> +<div class="content"> +<pre>The Reset() method send the STMP RSET command to the server.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This command clear the current buffer on MAIL, RCPT, and DATA, but not the +EHLO/HELO buffer.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>On success, it will return response with Code 250, StatusOK.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes_2">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/ascii: fix IsHex return false on 0</p> +</li> +<li> +<p>lib/memfs: fix parent empty directory not removed</p> +<div class="literalblock"> +<div class="content"> +<pre>Use case:</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>x +x/y</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>If x/y is empty, and x processed first, the x will +not be removed.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit fix this, by sorting the paths in descending order first +to make empty parent removed clearly. In above case the order +or check become,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>x/y +x</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, update an example of New to give preview of input and +what the expected output for certain operations.</pre> +</div> +</div> +</li> +<li> +<p>lib/xmlrpc: rewrite the Client connection using lib/http</p> +<div class="literalblock"> +<div class="content"> +<pre>Using socket connection require reading the HTTP response header before +we can process the response body.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Instead of rewrite the parser, use the lib/http to send and receive +the request/response.</pre> +</div> +</div> +</li> +<li> +<p>lib/io: do not use absolute path on dummy Watcher parent SysPath</p> +<div class="literalblock"> +<div class="content"> +<pre>Converting that parameter path to absolute path may cause unpredictable +result on module that use it.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_chores_1">Chores</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/ini: add example of marshal/unmarshaling of section with sub</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes also fix the example of field tag on marshaling the +map.</pre> +</div> +</div> +</li> +<li> +<p>lib/io: add method String to FileState type</p> +<div class="literalblock"> +<div class="content"> +<pre>The String method return the string representation of FileState. +Usually used only for debugging.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: remove unnecessary initialization on NewNode</p> +<div class="literalblock"> +<div class="content"> +<pre>The zero value for V ([]byte) is already nil and Node.Childs +([]*Node) does not need to be initialized with make if size is 0.</pre> +</div> +</div> +</li> +<li> +<p>lib/io: use t.Cleanup instead of defer on test</p> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_30_0_2021_10_04">share v0.30.0 (2021-10-04)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_breaking_changes_3">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/io: separate FileState for updated mode and content</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, when content of file being watched is modified, it will +trigger the callback with State set to FileStateModified. When the +mode of file is modified, it will also trigger the callback with +the same state.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes separated those state into two kind: FileStateUpdateMode +for update on file mode, and FileStateUpdateContent for update on +file content.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_new_features_3">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: export the Node Update method</p> +<div class="literalblock"> +<div class="content"> +<pre>The Update method update the node metadata or content based on new +file information. +It accept two parameters: the new file information, newInfo, and +maximum file size, maxFileSize.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The newInfo parameter is optional, if its nil, it will read the file +information based on node's SysPath.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The maxFileSize parameter is also optional. +If its negative, the node content will not be updated. +If its zero, it will default to 5 MB.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>There are two possible changes that will happen: its either change on +mode or change on content (size and modtime). +Change on mode will not affect the content of node.</pre> +</div> +</div> +</li> +<li> +<p>lib/strings: add function Alnum</p> +<div class="literalblock"> +<div class="content"> +<pre>The Alnum remove non alpha-numeric character from text and return it. +Its accept the string to be cleanup and boolean parameter withSpace. +If withSpace is true then white space is allowed, otherwise it would +also be removed from text.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes_3">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: fix symlink to directory not included on mount</p> +<div class="literalblock"> +<div class="content"> +<pre>During mounting and scanning a directory, if the node is symlink to a +directory, the isIncluded will return false because the node is not +a file nor directory.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The fix is to check if node mode is symlink first and then get the +the real stat.</pre> +</div> +</div> +</li> +<li> +<p>lib/io: fix NewWatcher when called DirWatcher</p> +<div class="literalblock"> +<div class="content"> +<pre>When NewWatcher called from DirWatcher's Start(), it will called NewNode +with nil parent parameter. If the parent parameter is nil on NewNode +the SysPath of new node will be set to the FileInfo.Name() instead of +full or relative path based on current working directory.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Any operation using new node SysPath will failed because the path +does not exist or reachable from current directory.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>For example, let say we have the following directory tree,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>testdata +| ++--- A +| ++--- B</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>We then set DirWatcher Root to "testdata" from current directory. +The DirWatcher Start then iterate over all child of "testdata" directory, +and call NewWatcher("testdata/A", ...). On the NewWatcher, it will +call NewNode(nil, FileInfo, -1). Now since the parent is nil, +the Node.SysPath will be set to FileInfo.Name() or base name of the file, +which is "A".</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Later, when node content need to be read, ioutil.ReadFile("A") will +fail because the path to "A" does not exist on current directory.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This fix require to force the parameter "parent" on NewNode to be +required.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: fix possible data race on PathNode</p> +<div class="literalblock"> +<div class="content"> +<pre>During Memfs Get(), if the node returned by PathNodes.Get() is null, +the memfs instance will try to refresh the directory tree. In case +the requested path exist, the memfs will write to PathNodes through +AddChild()</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>At the same time, there maybe a request to access another path, which +cause both read and write occured.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: fix NewNode if node is symlink to directory</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, if a symlink point to directory the memfs NewNode function +will return an error,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>AddChild wui: NewNode: read x/y: is a directory</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>which cause the files inside y cannot be scanned (404).</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit fix this issue by checking if the original node mode is a +directory and return immediately.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_2">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: check error on File Close on GoGenerate</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we ignore the error for call to Close when there is an +error in previous operation.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes check the error returned from Close and add it to the +returned error message.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, use consisten prefix for all returned error: +"MemFS.GoGenerate".</pre> +</div> +</div> +</li> +<li> +<p>lib/http: support server caching file system using ETag</p> +<div class="literalblock"> +<div class="content"> +<pre>If the Server handle file system using MemFS, server will set the +ETag [1] header using the file epoch as value.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>On the next request, server will compare the request header +If-None-Match with the requested file epoch. If its equal server will +return the response as 304 StatusNotModified.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag</pre> +</div> +</div> +</li> +<li> +<p>lib/xmlrpc: convert the value using Sprintf on GetFieldAsString</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the GetFieldAsString will return empty string if the +Value type is not string.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>In this commit, we force the value to be string by converted it using +fmt.Sprintf.</pre> +</div> +</div> +</li> +<li> +<p>math/big: add some examples of Rat.Int64() and RoundToNearestAway</p> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_chores_2">Chores</h3> +<div class="ulist"> +<ul> +<li> +<p>github: update the Go version to v1.17.1</p> +</li> +<li> +<p>lib/strings: update comment and example of TrimAlnum</p> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_29_2_2021_09_06">share v0.29.2 (2021-09-06)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_bug_fixes_4">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>os/exec: fix escaped quote inside the same quote</p> +<div class="literalblock"> +<div class="content"> +<pre>Shell quote is a hell of complex. For example, one can write +shell that execute command that contains quote of quote,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>sh -c "psql -c 'CREATE ... IDENTIFIED BY PASSWORD '\''pass'\'''"</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>or to simplify,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>sh -c "psql -c \"CREATE ... IDENTIFIED BY PASSWORD 'pass'\""</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: fix empty ContentType if MaxFileSize is negative</p> +<div class="literalblock"> +<div class="content"> +<pre>A negative MaxFileSize means the content of file will not be mapped to +memory, but the content type should be detected for other operation.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: fix empty file not being added to tree</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we did not check if the file size is 0 before reading the +content or updating the content type, which cause the read on file +return io.EOF and the file not added to caches.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit fix this issue by checking for zero file size and for +io.EOF when reading the file content.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: fix symbolic link with different name</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, if file is symbolic link and has different name with their +original file, it will return an error when we tried to open the file</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>parentpath/filename: no such file or directory</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>because we use the original file name, not the symlinked file name.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit fix this issue by not replacing the original FileInfo for +symlink but by setting only the size and mode.</pre> +</div> +</div> +</li> +<li> +<p>lib/sql: do not run migration if the last file not exist on the list</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, if the last migrated file name not found on the migration +directory, we start executing migration start from the first file.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes the behaviour to not run any migration at all. +Since we cannot return it as an error, we only log it. In the future +we may return it.</pre> +</div> +</div> +</li> +<li> +<p>lib/http: fix missing content type for XML Header</p> +<div class="literalblock"> +<div class="content"> +<pre>If the Endpoint set the RequestType to RequestTypeXML, the response +header should be set to ContentTypeXML.</pre> +</div> +</div> +</li> +<li> +<p>lib/xmlrpc: fix missing port on NewClient</p> +<div class="literalblock"> +<div class="content"> +<pre>Calling net.Dial or tls.Dial on host without port will cause the +following error,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>NewClient: Dial: dial tcp: address 10.148.0.164: missing port in address</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes fix this by always generate new host value using previous +host and port values.</pre> +</div> +</div> +</li> +<li> +<p>lib/smtp: return io.EOF if no data received from server</p> +<div class="literalblock"> +<div class="content"> +<pre>This is to prevent the recv return nil on *Response without an error, +which may cause panic on caller side.</pre> +</div> +</div> +</li> +<li> +<p>os/exec: check for escaped backslash when ParseCommandArgs</p> +<div class="literalblock"> +<div class="content"> +<pre>Given the following string "cmd /a\ b" to ParseCommandArgs now +return "cmd" and ["/a b"] not ["/a\", "b"], because the space after a +is escaped using backslash.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_3">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/memfs: set default content type for empty file to "text/plain"</p> +<div class="literalblock"> +<div class="content"> +<pre>An empty file should be able to be displayed as text file instead of +downloaded as binary.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: change the MarshalJSON to always return an object</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, MarshalJSON on memfs will return an object of map +of all PathNodes and on Node it will return an object.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes make it the JSON response consistent. If its directory +it will return the node object with its childs, without "content". +If its file, it will return the node object with content.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, use single "mod_time" with value is epoch and return +the node ContentType as "content_type".</pre> +</div> +</div> +</li> +<li> +<p>lib/mlog: implement io.Writer and add function ErrorWriter</p> +<div class="literalblock"> +<div class="content"> +<pre>The ErrorWriter will return the internal default MultiLogger. +A call to Write() on returned io.Writer will forward it to all registered +error writers.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>A Write method on MultiLogger write the b to all error writers. +It will always return the length of b without an error.</pre> +</div> +</div> +</li> +<li> +<p>lib/memfs: add method Save and Encode</p> +<div class="literalblock"> +<div class="content"> +<pre>The Save method will write the new content to file system and update +the content of Node using Encode().</pre> +</div> +</div> +</li> +<li> +<p>lib/ssh: add method to set session output and error</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, all of the SSH output and error goes to os.Stdout and +os.Stderr.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes add method SetSessionOutputError to change the output and +error for future remote execution.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_chores_3">Chores</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/reflect: make the IsNil tests to become an example</p> +<div class="literalblock"> +<div class="content"> +<pre>In this way we do test and provide an example at the same time.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, add another test cases for boolean, initialized slice, map, +and errors.</pre> +</div> +</div> +</li> +<li> +<p>lib/websocket: try to fix flaky test on client</p> +<div class="literalblock"> +<div class="content"> +<pre>The following error thrown when running on Github Action using +Ubuntu-latest and Go 1.16.3,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>client_test.go:472: write tcp 127.0.0.1:34460->127.0.0.1:9001: +write: connection reset by peer</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This may be caused by using the same client connection on all test +cases.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>We try to fix this by creating new client on each test cases.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_29_1_2021_08_06">share v0.29.1 (2021-08-06)</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p>Revert the "lib/errors: return the internal error only if its not nil on +Unwrap".</p> +</div> +<div class="paragraph"> +<p>Returning instance of e on Unwrap will cause recursive call.</p> +</div> +<div class="paragraph"> +<p>The correct solution to convert an error to errors.E is by implementing the As +method.</p> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_29_0_2021_08_06">share v0.29.0 (2021-08-06)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_new_feature">New feature</h3> +<div class="paragraph"> +<p>ssh/sftp: new package that implement SSH File Transport Protocol v3</p> +</div> +<div class="paragraph"> +<p>The sftp package extend the golang.org/x/crypto/ssh package by +implementing "sftp" subsystem using the ssh.Client connection.</p> +</div> +</div> +<div class="sect2"> +<h3 id="_breaking_changes_4">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>text/diff: add functions to compare raw bytes as text and text.Lines</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes refactoring some functions, notably,</pre> +</div> +</div> +</li> +<li> +<p>Rename Bytes function to IsEqual</p> +</li> +<li> +<p>Rename Lines function to Bytes</p> +</li> +<li> +<p>Add function Text that compare two text (raw bytes)</p> +</li> +<li> +<p>Add function Lines that compare two instances of text.Lines</p> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_4">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/mlog: add function and method Panicf</p> +<div class="literalblock"> +<div class="content"> +<pre>The Panicf method is equal to Errf followed by panic. This signature +follow the log.Panicf convention.</pre> +</div> +</div> +</li> +<li> +<p>lib/text: implement function to parse raw bytes into Lines</p> +</li> +<li> +<p>lib/text: implement Stringer on Chunk and Line types</p> +</li> +<li> +<p>lib/memfs: implement json.Marshaler on MemFS and Node</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, without MarshalJSON, encoding the MemFS or Node object will +result in incomplete information, for example, missing name, modification +time, and size.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit implement the json.Marshaler in MemFS which encode the +PathNode sorted by keys in ascending order.</pre> +</div> +</div> +</li> +<li> +<p>lib/bytes: print the ASCII character on the right side on PrintHex</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, PrintHex only print the hex value of all bytes with +specified length.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes also print any printables ASCII characters (char 33 through +126) in the right side column to view readable contents.</pre> +</div> +</div> +</li> +<li> +<p>lib/totp: lib/totp: increase the maximum steps back on Verify from 2 to 20</p> +<div class="literalblock"> +<div class="content"> +<pre>The value 20 means the Verify will check maximum 20 TOTP tokens or 10 +minutes to the past.</pre> +</div> +</div> +</li> +<li> +<p>lib/http: check request path as HTML file on getFSNode</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, if the request path is not exist we check if request +contains index.html and if still not exist we return nil.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit add another check by appending ".html" to the request path.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>So, for example, if path "/x" not exist in memfs, we check if +"/x/index.html". If its still not exist, we check "/x.html".</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fix">Bug fix</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/errors: return the internal error only if its not nil on Unwrap</p> +<div class="literalblock"> +<div class="content"> +<pre>If the internal error is nil, the Unwrap method will return the instance +of e itself.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_28_0_2021_07_06">share v0.28.0 (2021-07-06)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_breaking_changes_5">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>lib/ssh: rename method Get to ScpGet and Put to ScpPut</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes is to make clear that the methods to copy the files, either +from local or from remote, is using the "scp" through exec package, +not using the native SSH file transfer protocol.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, use consistent log prefix for error message.</pre> +</div> +</div> +</li> +<li> +<p>ssh: rename the NewClient function to NewClientFromConfig</p> +<div class="literalblock"> +<div class="content"> +<pre>This is to differentiate it with x/crypto ssh package that have the same +function name.</pre> +</div> +</div> +</li> +<li> +<p>ssh: move the config parser to subpackage "config"</p> +<div class="literalblock"> +<div class="content"> +<pre>There are two reasons for moving to sub-package. First, the code for +parsing the ssh_config(5) take almost 99% of the lines in the ssh package. +Second, in case we want to submit the code to upstream, +golang.org/x/crypto, we need the package to be independent, less external +dependencies as possible.</pre> +</div> +</div> +</li> +<li> +<p>http: remove the Memfs field from Server</p> +<div class="literalblock"> +<div class="content"> +<pre>Now that Options field has been exported, we did not need to have +duplicate Memfs, so this field is removed in favor of Options.Memfs.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_5">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>websocket: export the Options field on the Server</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the Options field is not exported to prevent user from +changing it once it set through NewServer() function.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes export the Options field to allow user of Server access its +values. We can create a method on server to return read-only options, +but that will over complicated the Server API.</pre> +</div> +</div> +</li> +<li> +<p>http: export the Options field on the Server</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the Options field is not exported to prevent user from +changing it once it set through NewServer() function.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes export the Options field to allow user of Server access its +values. We can create a method on server to return read-only options, +but that will over complicated the Server API.</pre> +</div> +</div> +</li> +<li> +<p>websocket: store all the handshake headers to Handshake.Header</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously only non-required headers are stored in the Handshake Header +field, while the required header value stored on their respective fields.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit store all request header key and values into the Header field.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_27_0_2021_06_05">share v0.27.0 (2021-06-05)</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p>This release bring better functionalities, usability, and fixes for <code>xmlrpc</code> +package.</p> +</div> +<div class="sect2"> +<h3 id="_breaking_changes_6">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>xmlrpc: change the Response to embed the errors.E</p> +<div class="literalblock"> +<div class="content"> +<pre>The errors.E contains code and message that also implement wrapping and +unwrapping error, so we can use the Response as error just like in +http.EndpointResponse.</pre> +</div> +</div> +</li> +<li> +<p>xmlrpc: write the XML header when marshaling request not on client</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the XML header is added when sending the request using +client.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit changes it to write the header when marshaling the Request +instance.</pre> +</div> +</div> +</li> +<li> +<p>xmlrpc: replace Value field for struct with map of string and value</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, for param with type "struct" is represented by slice of +Member{Name,Value}.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit changes the Value field for "struct" to a map of string and +value for easily access the struct's member, without looping.</pre> +</div> +</div> +</li> +<li> +<p>xmlrpc: refactoring the parser for decoding XML-RPC request</p> +<div class="literalblock"> +<div class="content"> +<pre>This changes,</pre> +</div> +</div> +</li> +<li> +<p>method to parse XML-RPC request,</p> +</li> +<li> +<p>change the Member field Value type to pointer to Value,</p> +</li> +<li> +<p>change the Request field Params type to slice of pointer of Value,</p> +</li> +<li> +<p>change the Response field Param type to pointer to Value,</p> +</li> +<li> +<p>rename the Value fields from Members to StructMembers and Values to +ArrayValues</p> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_new_features_4">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>memfs: add function to Merge one or more instance of MemFS</p> +<div class="literalblock"> +<div class="content"> +<pre>The Merge function merge one or more instance of MemFS into single MemFS +instance.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>If there are two instance of Node that have the same path, the last +instance will be ignored.</pre> +</div> +</div> +</li> +<li> +<p>xmlrpc: add method to marshal Response</p> +</li> +<li> +<p>mlog: add function and method PrintStack</p> +<div class="literalblock"> +<div class="content"> +<pre>The PrintStack function or method will writes to error writers the stack +trace returned by debug.Stack.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_6">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>http: add request type for XML</p> +<div class="literalblock"> +<div class="content"> +<pre>Setting Endpoint's RequestType to RequestTypeXML will check the content +type of HTTP request to match with "text/xml".</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes_5">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>memfs: set the field Parent on Node AddChild</p> +</li> +<li> +<p>xmlrpc: convert the uint8 and uint16 as type Integer, and Uint as Double</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, uint8 and uint16 will be converted as Double, but those +types are in range of four bytes so it can still be handled by int32.</pre> +</div> +</div> +</li> +<li> +<p>xmlrpc: set client response IsFault when StatusCode >= 400</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, we set IsFault to true if the HTTP response code not equal to +200 only, which is not always correct.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit changes it to check any status code that is greater or equal +to 400.</pre> +</div> +</div> +</li> +<li> +<p>memfs: fix test by checking multiple content-types</p> +<div class="literalblock"> +<div class="content"> +<pre>On Arch Linux with Go tip, the content-type for JavaScript file is +"text/javascript". While on Ubuntu with Go 1.16 the content-type for +JavaScript file is "application/javascript".</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_26_0_2021_05_03">share v0.26.0 (2021-05-03)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_new_features_5">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>math/big: add method Add, IsLess, IsGreater, and Scan on Int</p> +<div class="literalblock"> +<div class="content"> +<pre>The Add method simplify addition of one value to current Int.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The IsLess and IsGreater method simplify comparing Int with any value.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The Scan method allow the Int to be used on sql Scan().</pre> +</div> +</div> +</li> +<li> +<p>math/big: add method IsZero on Int</p> +<div class="literalblock"> +<div class="content"> +<pre>The IsZero method will return true if the current i value is zero.</pre> +</div> +</div> +</li> +<li> +<p>big: extends the standard big.Int</p> +<div class="literalblock"> +<div class="content"> +<pre>The standard big.Int does not implement sql/driver.Valuer interface, +which make it not usable when querying or doing update/insert with +database.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This commit extend the big.Int and simplify creating new Int from any +values using NewInt().</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Also, make it support marshal/unmarshal JSON</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_7">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>sql: make the column filename on table _migration as primary key</p> +<div class="literalblock"> +<div class="content"> +<pre>This will allow deleting the record by filename instead of requiring +all columns.</pre> +</div> +</div> +</li> +<li> +<p>http: add the Total field to EndpointResponse</p> +<div class="literalblock"> +<div class="content"> +<pre>The Total field contains the total number of all records, while the +Count fields only contains the total number of records in Data.</pre> +</div> +</div> +</li> +<li> +<p>http: add field Page to EndpointResponse</p> +<div class="literalblock"> +<div class="content"> +<pre>The page field contains the requested page on current response. +If page is from request then the offset will be set to page times limit.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>While at it, move the field comment to its declaration.</pre> +</div> +</div> +</li> +<li> +<p>big: allow creating new Rat from uint64 and *big.Int</p> +</li> +<li> +<p>ssh: check for empty private key file on Get and Put</p> +<div class="literalblock"> +<div class="content"> +<pre>If the private key file is empty, skip it for being added as parameter +of scp command. This is to prevent warning message on user side.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_chores_4">Chores</h3> +<div class="ulist"> +<ul> +<li> +<p>memfs: update the test ContentType for JavaScript files</p> +<div class="literalblock"> +<div class="content"> +<pre>The latest Go set the content type for JavaScript file as +"text/javascript; charset=utf-8", not "application/javascript".</pre> +</div> +</div> +</li> +<li> +<p>paseto: replace le64() function with binary.Write()</p> +<div class="literalblock"> +<div class="content"> +<pre>The le64() return the string representation of uint64 in little endian, +which is basically binary.Write with parameter output buffer, +LittleEndian, and input value.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_25_1_2021_04_06">share v0.25.1 (2021-04-06)</h2> +<div class="sectionbody"> +<div class="paragraph"> +<p>Set the minimum Go version to 1.16</p> +</div> +<div class="paragraph"> +<p>Commit 4cdd6b01c1 "http: add method to generate standard HTTP request +on Client" use the io.NopCloser thats only available in Go 1.16. Either +we move backward by replacing it with ioutil.NopCloser or we move forward +by setting the minimum Go version to 1.16.</p> +</div> +<div class="paragraph"> +<p>We choose to move forward.</p> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_25_0_2021_04_06">share v0.25.0 (2021-04-06)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_breaking_changes_7">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> +<p>all: refactoring the test.Assert and test.AssertBench signature</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the test.Assert and test.AssertBench functions has the +boolean parameter to print the stack trace of test in case its not equal.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>Since this parameter is not mandatory and its usually always set to +"true", we remove them from function signature to simplify the call +to Assert and AssertBench.</pre> +</div> +</div> +</li> +<li> +<p>all: refactoring http.Client methods signature</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, parameters to method Delete, Get, Post, PostForm, PostFormData, +PostJSON, Put, and PutJSON are in the following order:</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>(headers, path, params)</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This is sometimes confusing. To make it better and works with format +of HTTP request header,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>METHOD PATH +HEADERS</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>PARAMS</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>we move the path to the first parameter and headers as the second +parameter, so the call to client methods would be</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>(path, headers, params)</pre> +</div> +</div> +</li> +<li> +<p>http: remove parameter contentType on Client method Put</p> +<div class="literalblock"> +<div class="content"> +<pre>Since one can set the Content-Type in parameter headers, this parameter is +become redundant.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_new_features_6">New features</h3> +<div class="ulist"> +<ul> +<li> +<p>http: add method to generate standard HTTP request on Client</p> +<div class="literalblock"> +<div class="content"> +<pre>The GenerateHttpRequest method generate http.Request instance from +method, path, requestType, headers, and params.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>For HTTP method GET, CONNECT, DELETE, HEAD, OPTIONS, or TRACE; the params +value should be nil or url.Values. +If its url.Values, then the params will be encoded as query parameters.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>For HTTP method is PATCH, POST, or PUT; the params will converted based on +requestType rules below,</pre> +</div> +</div> +</li> +<li> +<p>If requestType is RequestTypeQuery and params is url.Values it will be +added as query parameters in the path.</p> +</li> +<li> +<p>If requestType is RequestTypeForm and params is url.Values it will be +added as URL encoded in the body.</p> +</li> +<li> +<p>If requestType is RequestTypeMultipartForm and params type is +map[string][]byte, then it will be converted as multipart form in the +body.</p> +</li> +<li> +<p>If requestType is RequestTypeJSON and params is not nil, the params will +be encoded as JSON in body.</p> +</li> +<li> +<p>ssh: ask for passphrase if private key is encrypted on generateSigners</p> +<div class="literalblock"> +<div class="content"> +<pre>In case the private key defined in IdentityFile is encrypted, prompt +for the passphrase on the screen and read it from stdin using +terminal.ReadPassword().</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes also remove call to generateSigners on postConfig(), +instead invoke it from NewClient() to minimize multiple calls to +generateSigners().</pre> +</div> +</div> +</li> +<li> +<p>ssh: use the SSH agent to authenticate on NewClient</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the client use the IdentityFile on ConfigSection to +Authenticate with the remote SSH server. In case the IdentityFile is +Encrypted with passphrase, each time NewClient is invoked it will ask +For passphrase.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>To minimize inputing the passphrase, we check if current use run the +SSH agent through SSH_AUTH_SOCK environment variable and use the agent +To generate signers.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This method need manual key added by user to SSH agent before calling +NewClient to make it works.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_8">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>xmlrpc: add debug statements to print request and response</p> +<div class="literalblock"> +<div class="content"> +<pre>The debug level is set minimum to 3. If its set it will print the +request and response to standard output.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +</div> +</div> +<div class="sect1"> +<h2 id="_share_v0_24_0_2021_03_06">share v0.24.0 (2021-03-06)</h2> +<div class="sectionbody"> +<div class="sect2"> +<h3 id="_breaking_changes_8">Breaking changes</h3> +<div class="ulist"> +<ul> +<li> <p>http: add prefix Header to constants AcceptEncoding and ContentEncoding</p> <div class="literalblock"> <div class="content"> @@ -478,11 +2897,52 @@ is "postgres" the place holders will be returned as counter, for example </div> </div> </li> +<li> +<p>http: rename "GenericResponse" to "EndpointResponse"</p> +<div class="literalblock"> +<div class="content"> +<pre>Well, the hard thing in software is naming a thing. Using the term +Generic is too generic, so we change it to make it closer with Endpoint.</pre> +</div> +</div> +</li> +<li> +<p>http: refactoring parameters on Callback and CallbackErrorHandler</p> +<div class="literalblock"> +<div class="content"> +<pre>Previously, the parameters to Callback has three types: +the http.ResponseWriter, *http.Request, and []byte for response body. +Not only the type names are long, there is no information on the +registered Endpoint on the receiver of Callback.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes wrap the three parameters into single type EndpointRequest +with addition field Endpoint, which contains the registered Endpoint.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>On the CallbackErrorHandler we also have three parameters, but instead +of request body we have an error.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>This changes store the error for CallbackErrorHandler inside +EndpointRequest.Error field.</pre> +</div> +</div> +</li> +<li> +<p>http: move the CORS options to separate struct</p> +</li> </ul> </div> </div> <div class="sect2"> -<h3 id="_new_features">New features</h3> +<h3 id="_new_features_7">New features</h3> <div class="ulist"> <ul> <li> @@ -589,6 +3049,106 @@ If the request Method is HEAD, only the header will be sent back to client.</pre </div> </div> </li> +<li> +<p>clise: add method Pop</p> +<div class="literalblock"> +<div class="content"> +<pre>The Pop method remove the last Push()-ed item and return it to caller. +It will return nil if no more item inside it.</pre> +</div> +</div> +</li> +<li> +<p>ini: add support for marshaling slice of struct</p> +<div class="literalblock"> +<div class="content"> +<pre>Given a struct with exported field is slice of struct and tagged with +section and sub-section, the exported field will be marshalled as,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>[section "sub"] +field = value</pre> +</div> +</div> +</li> +<li> +<p>ini: add support for marshaling pointer to struct and to time.Time</p> +<div class="literalblock"> +<div class="content"> +<pre>Given the following field struct with tag,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>V *T `ini:"sec:sub"</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>If the V is not nil, it will marshal it into,</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>[sec "sub"] +<field name or tag> = <field value></pre> +</div> +</div> +</li> +<li> +<p>ini: add support for un-marshaling to struct and slice of struct</p> +</li> +<li> +<p>big: add method that implement sql/driver.Valuer for type Rat</p> +<div class="literalblock"> +<div class="content"> +<pre>The Rat.Value() return the value as []byte.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_enhancements_9">Enhancements</h3> +<div class="ulist"> +<ul> +<li> +<p>clise: make all methods safe for concurrent use</p> +</li> +<li> +<p>http: add fields for paging on GenericResponse</p> +<div class="literalblock"> +<div class="content"> +<pre>If the response is paging, contains more than one item in data, one +can set the current status of paging in field Offset, Limit, and Count.</pre> +</div> +</div> +<div class="literalblock"> +<div class="content"> +<pre>The Offset field contains the start of paging. +The Limit field contains the maximum number of records per page. +The Count field contains the total number of records.</pre> +</div> +</div> +</li> +</ul> +</div> +</div> +<div class="sect2"> +<h3 id="_bug_fixes_6">Bug fixes</h3> +<div class="ulist"> +<ul> +<li> +<p>reflect: check using equal statement on IsNil</p> +<div class="literalblock"> +<div class="content"> +<pre>Beside using IsNil(), return the last check using "v == nil".</pre> +</div> +</div> +</li> </ul> </div> </div> @@ -605,7 +3165,7 @@ or more directories in single package.</p> <p>The minimum Go version is increased to 1.14.</p> </div> <div class="sect2"> -<h3 id="_breaking_changes_1">Breaking changes</h3> +<h3 id="_breaking_changes_9">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -729,7 +3289,7 @@ predictable.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_1">New features</h3> +<h3 id="_new_features_8">New features</h3> <div class="ulist"> <ul> <li> @@ -818,7 +3378,7 @@ value from fraction.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements">Enhancements</h3> +<h3 id="_enhancements_10">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -849,7 +3409,7 @@ most of its fields, so consumer can access it.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes">Bug fixes</h3> +<h3 id="_bug_fixes_7">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -888,7 +3448,7 @@ file.</pre> <h2 id="_share_v0_22_0_2021_01_06">share v0.22.0 (2021-01-06)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_2">Breaking changes</h3> +<h3 id="_breaking_changes_10">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -901,7 +3461,7 @@ file.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_2">New features</h3> +<h3 id="_new_features_9">New features</h3> <div class="ulist"> <ul> <li> @@ -920,7 +3480,7 @@ secret key.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_1">Enhancements</h3> +<h3 id="_enhancements_11">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -945,7 +3505,7 @@ standard output.</pre> <h2 id="_share_v0_21_0_2020_12_06">share v0.21.0 (2020-12-06)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_3">Breaking changes</h3> +<h3 id="_breaking_changes_11">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -961,7 +3521,7 @@ which describe which field have unmatched value.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_3">New features</h3> +<h3 id="_new_features_10">New features</h3> <div class="ulist"> <ul> <li> @@ -991,7 +3551,7 @@ RFC 6238.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_1">Bug fixes</h3> +<h3 id="_bug_fixes_8">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1018,7 +3578,7 @@ method always return "b, 0" on the last line.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_2">Enhancements</h3> +<h3 id="_enhancements_12">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1053,7 +3613,7 @@ paremeter) or valid IP address.</pre> </div> </div> <div class="sect2"> -<h3 id="_chores">Chores</h3> +<h3 id="_chores_5">Chores</h3> <div class="ulist"> <ul> <li> @@ -1074,7 +3634,7 @@ tools.</pre> <h2 id="_share_v0_20_1_2020_11_08">share v0.20.1 (2020-11-08)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_bug_fixes_2">Bug fixes</h3> +<h3 id="_bug_fixes_9">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1090,7 +3650,7 @@ not look like a TLS handshake".</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_3">Enhancements</h3> +<h3 id="_enhancements_13">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1122,7 +3682,7 @@ position, and then call Close to reset the internal state back to zero.</pre> </div> </div> <div class="sect2"> -<h3 id="_chores_1">Chores</h3> +<h3 id="_chores_6">Chores</h3> <div class="ulist"> <ul> <li> @@ -1137,7 +3697,7 @@ position, and then call Close to reset the internal state back to zero.</pre> <h2 id="_share_v0_20_0_2020_10_05">share v0.20.0 (2020-10-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_new_features_4">New features</h3> +<h3 id="_new_features_11">New features</h3> <div class="ulist"> <ul> <li> @@ -1159,7 +3719,7 @@ handled and filled automatically.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_4">Enhancements</h3> +<h3 id="_enhancements_14">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1181,7 +3741,7 @@ is forwarded to DNS server, so this changes accommodated it.</p> <h2 id="_share_v0_19_0_2020_09_08">share v0.19.0 (2020-09-08)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_4">Breaking changes</h3> +<h3 id="_breaking_changes_12">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1235,7 +3795,7 @@ Messages.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_5">New features</h3> +<h3 id="_new_features_12">New features</h3> <div class="ulist"> <ul> <li> @@ -1281,7 +3841,7 @@ previously) and new path and handler for retrieving server status.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_3">Bug fixes</h3> +<h3 id="_bug_fixes_10">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1305,7 +3865,7 @@ previously) and new path and handler for retrieving server status.</pre> <h2 id="_share_v0_18_0_2020_08_06">share v0.18.0 (2020-08-06)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_5">Breaking changes</h3> +<h3 id="_breaking_changes_13">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1343,7 +3903,7 @@ if the library always set the response type to None.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_4">Bug fixes</h3> +<h3 id="_bug_fixes_11">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1353,7 +3913,7 @@ if the library always set the response type to None.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_5">Enhancements</h3> +<h3 id="_enhancements_15">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1383,7 +3943,7 @@ if the library always set the response type to None.</pre> <h2 id="_share_v0_17_0_2020_07_05">share v0.17.0 (2020-07-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_6">Breaking changes</h3> +<h3 id="_breaking_changes_14">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1399,7 +3959,7 @@ if the library always set the response type to None.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_5">Bug fixes</h3> +<h3 id="_bug_fixes_12">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1415,7 +3975,7 @@ if the library always set the response type to None.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_6">Enhancements</h3> +<h3 id="_enhancements_16">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1445,7 +4005,7 @@ if the library always set the response type to None.</pre> <h2 id="_share_v0_16_0_2020_06_05">share v0.16.0 (2020-06-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_7">Breaking changes</h3> +<h3 id="_breaking_changes_15">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1508,7 +4068,7 @@ become unneeded, so we remove them.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_6">Bug fixes</h3> +<h3 id="_bug_fixes_13">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1518,7 +4078,7 @@ become unneeded, so we remove them.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_6">New features</h3> +<h3 id="_new_features_13">New features</h3> <div class="ulist"> <ul> <li> @@ -1587,7 +4147,7 @@ file name that has been executed and the timestamp.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_7">Enhancements</h3> +<h3 id="_enhancements_17">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1648,7 +4208,7 @@ fis, err := root.Readdir(0)</pre> <h2 id="_share_v0_15_0_2020_05_04">share v0.15.0 (2020-05-04)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_8">Breaking changes</h3> +<h3 id="_breaking_changes_16">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1661,7 +4221,7 @@ fis, err := root.Readdir(0)</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_7">New features</h3> +<h3 id="_new_features_14">New features</h3> <div class="ulist"> <ul> <li> @@ -1695,7 +4255,7 @@ to iterate each node in the tree from top to bottom.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_8">Enhancements</h3> +<h3 id="_enhancements_18">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1717,7 +4277,7 @@ to iterate each node in the tree from top to bottom.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_7">Bug fixes</h3> +<h3 id="_bug_fixes_14">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1732,7 +4292,7 @@ to iterate each node in the tree from top to bottom.</pre> <h2 id="_share_v0_14_0_2020_04_03">share v0.14.0 (2020-04-03)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_9">Breaking changes</h3> +<h3 id="_breaking_changes_17">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1753,7 +4313,7 @@ will be handled automatically based on value on field Method.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_8">New features</h3> +<h3 id="_new_features_15">New features</h3> <div class="ulist"> <ul> <li> @@ -1797,7 +4357,7 @@ single space ' '.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_9">Enhancements</h3> +<h3 id="_enhancements_19">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1831,7 +4391,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_8">Bug fixes</h3> +<h3 id="_bug_fixes_15">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1846,13 +4406,13 @@ word.</pre> <h2 id="_share_v0_13_0_2020_03_11">share v0.13.0 (2020-03-11)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_10">Breaking changes</h3> +<h3 id="_breaking_changes_18">Breaking changes</h3> <div class="paragraph"> <p>Set the minimum Go version to 1.13.</p> </div> </div> <div class="sect2"> -<h3 id="_new_features_9">New features</h3> +<h3 id="_new_features_16">New features</h3> <div class="ulist"> <ul> <li> @@ -1865,7 +4425,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_10">Enhancements</h3> +<h3 id="_enhancements_20">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1887,7 +4447,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_9">Bug Fixes</h3> +<h3 id="_bug_fixes_16">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -1905,7 +4465,7 @@ word.</pre> <h2 id="_share_v0_12_0_2020_02_13">share v0.12.0 (2020-02-13)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_11">Breaking changes</h3> +<h3 id="_breaking_changes_19">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1924,7 +4484,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_10">New features</h3> +<h3 id="_new_features_17">New features</h3> <div class="ulist"> <ul> <li> @@ -1940,7 +4500,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_11">Enhancements</h3> +<h3 id="_enhancements_21">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -1950,7 +4510,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_10">Bug fixes</h3> +<h3 id="_bug_fixes_17">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -1965,7 +4525,7 @@ word.</pre> <h2 id="_share_v0_11_0_2019_12_26">share v0.11.0 (2019-12-26)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_12">Breaking changes</h3> +<h3 id="_breaking_changes_20">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -1975,7 +4535,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_new_features_11">New features</h3> +<h3 id="_new_features_18">New features</h3> <div class="ulist"> <ul> <li> @@ -1994,7 +4554,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_12">Enhancements</h3> +<h3 id="_enhancements_22">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2010,7 +4570,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_11">Bug fixes</h3> +<h3 id="_bug_fixes_18">Bug fixes</h3> <div class="ulist"> <ul> <li> @@ -2025,7 +4585,7 @@ word.</pre> <h2 id="_share_v0_10_2_2019_12_07">share v0.10.2 (2019-12-07)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_bug_fixes_12">Bug Fixes</h3> +<h3 id="_bug_fixes_19">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2043,7 +4603,7 @@ word.</pre> <h2 id="_share_v0_10_1_2019_12_05">share v0.10.1 (2019-12-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_bug_fixes_13">Bug Fixes</h3> +<h3 id="_bug_fixes_20">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2092,7 +4652,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_13">Enhancements</h3> +<h3 id="_enhancements_23">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2137,7 +4697,7 @@ word.</pre> <h2 id="_share_v0_10_0_2019_11_05">share v0.10.0 (2019-11-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_new_features_12">New Features</h3> +<h3 id="_new_features_19">New Features</h3> <div class="ulist"> <ul> <li> @@ -2153,7 +4713,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_breaking_changes_13">Breaking Changes</h3> +<h3 id="_breaking_changes_21">Breaking Changes</h3> <div class="ulist"> <ul> <li> @@ -2166,7 +4726,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_enhancements_14">Enhancements</h3> +<h3 id="_enhancements_24">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2188,7 +4748,7 @@ word.</pre> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_14">Bug Fixes</h3> +<h3 id="_bug_fixes_21">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2218,7 +4778,7 @@ word.</pre> <h2 id="_share_v0_9_0_2019_10_08">share v0.9.0 (2019-10-08)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_new_features_13">New Features</h3> +<h3 id="_new_features_20">New Features</h3> <div class="ulist"> <ul> <li> @@ -2261,7 +4821,7 @@ http.Request.Form using Get method.</p> </div> </div> <div class="sect2"> -<h3 id="_breaking_changes_14">Breaking Changes</h3> +<h3 id="_breaking_changes_22">Breaking Changes</h3> <div class="ulist"> <ul> <li> @@ -2288,7 +4848,7 @@ to be an empty string, so "var" value is equal to "".</p> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_15">Bug Fixes</h3> +<h3 id="_bug_fixes_22">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2305,7 +4865,7 @@ no DNS queries forwarded to parent server.</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_15">Enhancements</h3> +<h3 id="_enhancements_25">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2330,7 +4890,7 @@ to Search the content.</p> <h2 id="_share_v0_8_2_2019_09_05">share v0.8.2 (2019-09-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_enhancements_16">Enhancements</h3> +<h3 id="_enhancements_26">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2380,7 +4940,7 @@ in directory.</p> <h2 id="_share_v0_8_1_2019_08_05">share v0.8.1 (2019-08-05)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_enhancements_17">Enhancements</h3> +<h3 id="_enhancements_27">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2418,7 +4978,7 @@ file, we want that file to be excluded from .go static source.</p> <h2 id="_share_v0_8_0_2019_07_09">share v0.8.0 (2019-07-09)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_breaking_changes_15">Breaking changes</h3> +<h3 id="_breaking_changes_23">Breaking changes</h3> <div class="ulist"> <ul> <li> @@ -2429,7 +4989,7 @@ package to <code>ascii</code> package.</p> </div> </div> <div class="sect2"> -<h3 id="_new_features_14">New Features</h3> +<h3 id="_new_features_21">New Features</h3> <div class="ulist"> <ul> <li> @@ -2439,7 +4999,7 @@ package to <code>ascii</code> package.</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_18">Enhancements</h3> +<h3 id="_enhancements_28">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2464,7 +5024,7 @@ package to <code>ascii</code> package.</p> simple API.</p> </div> <div class="sect2"> -<h3 id="_breaking_changes_16">Breaking Changes</h3> +<h3 id="_breaking_changes_24">Breaking Changes</h3> <div class="ulist"> <ul> <li> @@ -2477,7 +5037,7 @@ simple API.</p> </div> </div> <div class="sect2"> -<h3 id="_new_features_15">New Features</h3> +<h3 id="_new_features_22">New Features</h3> <div class="ulist"> <ul> <li> @@ -2490,7 +5050,7 @@ simple API.</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_19">Enhancements</h3> +<h3 id="_enhancements_29">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2548,7 +5108,7 @@ simple API.</p> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_16">Bug Fixes</h3> +<h3 id="_bug_fixes_23">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2602,7 +5162,7 @@ Most notable changes are adding caches and query forwarding (recursion), and removing the server handler.</p> </div> <div class="sect2"> -<h3 id="_breaking_changes_17">Breaking Changes</h3> +<h3 id="_breaking_changes_25">Breaking Changes</h3> <div class="ulist"> <ul> <li> @@ -2676,7 +5236,7 @@ removing the server handler.</p> </div> </div> <div class="sect2"> -<h3 id="_new_features_16">New Features</h3> +<h3 id="_new_features_23">New Features</h3> <div class="ulist"> <ul> <li> @@ -2746,7 +5306,7 @@ removing the server handler.</p> </div> </div> <div class="sect2"> -<h3 id="_bug_fixes_17">Bug Fixes</h3> +<h3 id="_bug_fixes_24">Bug Fixes</h3> <div class="ulist"> <ul> <li> @@ -2812,7 +5372,7 @@ server and client API to make it easy and extensible. The websocket is now 100% pass the autobahn testsuite (minus compression feature).</p> </div> <div class="sect2"> -<h3 id="_new_features_17">New Features</h3> +<h3 id="_new_features_24">New Features</h3> <div class="ulist"> <ul> <li> @@ -2831,7 +5391,7 @@ server and client API to make it easy and extensible. The websocket is now </div> </div> <div class="sect2"> -<h3 id="_enhancements_20">Enhancements</h3> +<h3 id="_enhancements_30">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -2879,7 +5439,7 @@ testsuite</p> <h2 id="_share_v0_4_0_2019_03_01">share v0.4.0 (2019-03-01)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_new_features_18">New Features</h3> +<h3 id="_new_features_25">New Features</h3> <div class="ulist"> <ul> <li> @@ -2896,7 +5456,7 @@ testsuite</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_21">Enhancements</h3> +<h3 id="_enhancements_31">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -3091,7 +5651,7 @@ testsuite</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_22">Enhancements</h3> +<h3 id="_enhancements_32">Enhancements</h3> <div class="ulist"> <ul> <li> @@ -3131,7 +5691,7 @@ testsuite</p> <h2 id="_share_v0_2_0_2019_01_02">share v0.2.0 (2019-01-02)</h2> <div class="sectionbody"> <div class="sect2"> -<h3 id="_new_features_19">New Features</h3> +<h3 id="_new_features_26">New Features</h3> <div class="ulist"> <ul> <li> @@ -3145,7 +5705,7 @@ system and simplified routing handler.</p> </div> </div> <div class="sect2"> -<h3 id="_enhancements_23">Enhancements</h3> +<h3 id="_enhancements_33">Enhancements</h3> <div class="paragraph"> <p>Fix warnings from linters.</p> </div> @@ -3183,7 +5743,7 @@ and several libraries.</p> </div> <div id="footer"> <div id="footer-text"> -Last updated 2021-02-16 00:24:06 +0700 +Last updated 2022-01-09 23:57:53 +0700 </div> </div> </div> @@ -10,5 +10,5 @@ package share const ( // Version of this module. - Version = "0.32.0" + Version = "0.33.0" ) |
