summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-07-03 14:38:30 +0700
committerShulhan <ms@kilabit.info>2022-07-03 14:38:30 +0700
commit557cf80f27208fad7bf240ed400185e62d0684e8 (patch)
tree49f118398586ac47e7300cc7befe843cce4279e6
parent3a61112d7a4d1124354613a715cc23e5b2f0ab50 (diff)
downloadpakakeh.go-557cf80f27208fad7bf240ed400185e62d0684e8.tar.xz
doc: split changelog files by year
Since we release each month, the changelog growth bigger every times. In order to focus reader to latest changes, we move old changelogs to another files grouped by year.
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.adoc2716
-rw-r--r--_doc/CHANGELOG.html4867
-rw-r--r--_doc/CHANGELOG_2018-2019.adoc575
-rw-r--r--_doc/CHANGELOG_2020.adoc581
-rw-r--r--_doc/CHANGELOG_2021.adoc1598
-rw-r--r--_doc/index.adoc48
-rw-r--r--_doc/index.html86
8 files changed, 2867 insertions, 7605 deletions
diff --git a/.gitignore b/.gitignore
index d3afe736..b0f5efd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
*.stat
*.stats
*.test
+/_doc/*.html
/cmd/smtpcli/smtpcli
/gofmtcomment
/lib/dns/testdata/hosts.block.out
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index fa2ee594..0d8835a6 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -7,6 +7,16 @@ Shulhan <ms@kilabit.info>
This library is released every month, usually at the first week of month.
+link:CHANGELOG_2021.html[Changelog in 2021^].
+This is changelog for share module since v0.22.0 until v0.32.0.
+
+link:CHANGELOG_2020.html[Changelog in 2020^].
+This is changelog for share module since v0.12.0 until v0.21.0.
+
+link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^].
+This is changelog for share module since v0.1.0 until v0.11.0.
+
+
[#v0_38_0]
== share v0.38.0 (2022-06-05)
@@ -815,2709 +825,3 @@ The Go module should handle the dependencies automatically.
+
Since the ParseMailbox is public we can provide an examples and test
at the same times.
-
-
-[#v0_32_0]
-== share v0.32.0 (2021-12-03)
-
-This release bring major changes and enhancements to package dns and math/big.
-
-[#v0_32_0_breaking_changes]
-=== Breaking changes
-
-* math/big: refactoring AddFloat to accept variadic interface{}
-+
---
-Previously, the AddFloat function only accept two interface parameters.
-
-This changes make the AddFloat to accept many interface parameters.
---
-
-* math/big: refactor NewFloat to accept interface{} instead of float64 only
-+
-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.
-
-* math/big: refactoring the Rat
-+
---
-The promise of this package is to provide the Rat type with RoundToZero
-and without panic.
-
-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.
-
-Another breaking changes are,
-
-* Humanize() with nil pointer receiver will return string "0"
-* Any IsXxx() methods with nil pointer receiver will return false
-* MarshalJSON() will nil pointer receiver will return "null" instead of
- "0" now
---
-
-* lib/dns: refactoring, change signature of client Lookup
-+
---
-Previously, Lookup() method on Client pass the question name, type, and
-class as parameters.
-
-This changes make those parameters into MessageQuestion.
---
-
-* lib/dns: refactoring ZoneFile into Zone
-+
---
-Reason: A Zone is not always represented by file, it just that in this
-package, it is.
-
-This changes rename the type ZoneFile into Zone.
---
-
-* lib/dns: refactoring message question
-+
---
-Previously the type for message question section SectionQuestion.
-
-This changes, rename the type to MessageQuestion.
---
-
-* lib/dns: refactoring the section header
-+
---
-This changes rename the SectionHeader into MessageHeader.
-
-The pack() method is optimized with the following results,
-
-benchmark old ns/op new ns/op delta
-BenchmarkMessageHeader_pack-8 66.2 21.7 -67.31%
-
-benchmark old allocs new allocs delta
-BenchmarkMessageHeader_pack-8 3 1 -66.67%
-
-benchmark old bytes new bytes delta
-BenchmarkMessageHeader_pack-8 32 16 -50.00%
-
-The unpack() method is simplified by minimizing the if-condition.
-
-This changes also fix the pack and unpack OpCode for value other then 0,
-due to wrong shift value, 2 instead of 3.
---
-
-* lib/dns: refactoring, introduce new type RecordClass
-+
---
-Previously, the record class is represented by uint16 using prefix
-QueryClassXxx.
-
-This changes make the record class to be an independent type, to make
-code more strict (prevent passing invalid value), and readable.
---
-
-* lib/dns: refactoring, create type RecordType to represent type of RR
-+
---
-Previously, we use uint16 to represent type for ResourceRecord Type or
-Question type.
-
-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.
-
-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.
---
-
-* lib/dns: remove the fallback name servers (NS) from server options
-+
---
-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.
-
-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.
-
-This changes remove the unnecessary and complex fallback NS from
-server.
---
-
-[#v0_32_0_new_features]
-=== New features
-
-* lib/dns: add support to save and load caches to/from storage
-+
---
-The CachesSave method write the non-local answers into an io.Writer,
-encoded with gob.
-
-The CachesLoad method load the gob encoded answers from an io.Reader.
---
-
-* lib/ssh: use agent defined by config or from environment variable
-+
---
-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.
-
-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.
---
-
-* ssh/config: add support for section variable IdentityAgent
-+
-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.
-
-[#v0_32_0_bug_fixes]
-=== Bug fixes
-
-* math/big: return nil on Quo and QuoRat instead of panic
-+
---
-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.
-
-This changes make it less intrusive, instead of panic we check for
-zero value and return nil immediately.
---
-
-* lib/dns: do not cache truncated answer
-+
---
-Previously only answer with non-zero response code is ignored.
-
-This changes ignore also answer where response header is truncated.
---
-
-[#v0_32_0_enhancements]
-=== Enhancements
-
-* lib/dns: realign all struct fields
-+
---
-Turns out the struct that we frequently used, answer and resource_record,
-is not optimized.
-
- 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
-
-This changes reorder all structs field to save space in memory.
---
-
-* lib/dns: make the TCP forwarders as complementary of UDP
-+
---
-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.
-
-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.
---
-
-* lib/dns: use different packet between UDP and TCP messages
-+
---
-Previously, all packet size for reading and sending the message is
-fixed to 4096, even on UDP.
-
-This changes set the UDP packet size maximum to 512 bytes and others to
-4096 bytes.
-
-While at it, minimize copying packet if its not reusable inside a method.
---
-
-
-[#v0_31_0]
-== share v0.31.0 (2021-11-04)
-
-[#v0_31_0_breaking_changes]
-=== Breaking changes
-
-* lib/memfs: move the embedded parameter to Options
-+
---
-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.
-
-This commit add new type EmbedOptions that contains the parameters
-for GoEmbed.
-
-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.
---
-
-* lib/totp: make the New to accept only hash with SHA1, SHA256, or SHA512
-+
---
-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.
-
-This changes update the New function signature to accept defined
-type that can be set to SHA1, SHA256, or SHA512.
---
-
-* lib/bytes: refactoring and cleaning up the bytes package
-+
---
-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.
-
-A breaking changes,
-
-* 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.
-
-Bug fixes,
-
-* PrintHex: fix print layout on the last line
-* ReadHexByte: fix possible index out of range
-* SkipAfterToken return -1 and false if no token found, as promised
- in the comment, instead of the length of text.
-
-We move all unit test to example so we have test and example in the
-documentation at the same time.
-
-This changes make all test coverage 100%.
---
-
-* lib/bytes: refactoring AppendXxx functions
-+
-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.
-
-* lib/ascii: change signature of ToLower and ToUpper
-+
-Using pointer to slice on method or function is not a Go idiom.
-It is created when I still new to Go.
-
-* lib/memfs: refactoring Node field V into Content
-+
---
-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.
-
-Now, after having more time writing Go, I prefer clarity over
-cleverity(?).
---
-
-* lib/memfs: set the node modification time in embedded file
-+
---
-This changes set all node modification time in embedded files to
-the node modTime using Unix() and Nanosecond() values.
-
-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.
---
-
-[#v0_31_0_new_features]
-=== New features
-
-* lib/ini: add function IsValidVarName
-+
-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.
-
-* lib/memfs: set the node modification time in embedded file
-+
---
-This changes set all node modification time in embedded files to
-the node modTime using Unix() and Nanosecond() values.
-
-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.
---
-
-* lib/io: add method String to FileState type
-+
-The String method return the string representation of FileState.
-Usually used only for debugging.
-
-* lib/smtp: implement method Noop on Client
-+
---
-Noop send the NOOP command to server with optional message.
-
-On success, it will return response with Code 250, StatusOK.
-
-While at it fix double call to recv on Reset() method.
---
-
-* lib/smtp: implement method Reset on Client
-+
---
-The Reset() method send the STMP RSET command to the server.
-
-This command clear the current buffer on MAIL, RCPT, and DATA, but not the
-EHLO/HELO buffer.
-
-On success, it will return response with Code 250, StatusOK.
---
-
-[#v0_31_0_bug_fixes]
-=== Bug fixes
-
-* lib/ascii: fix IsHex return false on 0
-
-* lib/memfs: fix parent empty directory not removed
-+
---
-Use case:
-
- x
- x/y
-
-If x/y is empty, and x processed first, the x will
-not be removed.
-
-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,
-
- x/y
- x
-
-While at it, update an example of New to give preview of input and
-what the expected output for certain operations.
---
-
-* lib/xmlrpc: rewrite the Client connection using lib/http
-+
---
-Using socket connection require reading the HTTP response header before
-we can process the response body.
-
-Instead of rewrite the parser, use the lib/http to send and receive
-the request/response.
---
-
-* lib/io: do not use absolute path on dummy Watcher parent SysPath
-+
-Converting that parameter path to absolute path may cause unpredictable
-result on module that use it.
-
-[#v0_31_0_chores]
-=== Chores
-
-* lib/ini: add example of marshal/unmarshaling of section with sub
-+
-This changes also fix the example of field tag on marshaling the
-map.
-
-* lib/io: add method String to FileState type
-+
-The String method return the string representation of FileState.
-Usually used only for debugging.
-
-* lib/memfs: remove unnecessary initialization on NewNode
-+
-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.
-
-* lib/io: use t.Cleanup instead of defer on test
-
-
-[#v0_30_0]
-== share v0.30.0 (2021-10-04)
-
-[#v0_30_0_breaking_changes]
-=== Breaking changes
-
-* lib/io: separate FileState for updated mode and content
-+
---
-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.
-
-This changes separated those state into two kind: FileStateUpdateMode
-for update on file mode, and FileStateUpdateContent for update on
-file content.
---
-
-[#v0_30_0_new_features]
-=== New features
-
-* lib/memfs: export the Node Update method
-+
---
-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.
-
-The newInfo parameter is optional, if its nil, it will read the file
-information based on node's SysPath.
-
-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.
-
-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.
---
-
-* lib/strings: add function Alnum
-+
---
-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.
---
-
-[#v0_30_0_bug_fixes]
-=== Bug fixes
-
-* lib/memfs: fix symlink to directory not included on mount
-+
---
-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.
-
-The fix is to check if node mode is symlink first and then get the
-the real stat.
---
-
-* lib/io: fix NewWatcher when called DirWatcher
-+
---
-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.
-
-Any operation using new node SysPath will failed because the path
-does not exist or reachable from current directory.
-
-For example, let say we have the following directory tree,
-
- testdata
- |
- +--- A
- |
- +--- B
-
-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".
-
-Later, when node content need to be read, ioutil.ReadFile("A") will
-fail because the path to "A" does not exist on current directory.
-
-This fix require to force the parameter "parent" on NewNode to be
-required.
---
-
-* lib/memfs: fix possible data race on PathNode
-+
---
-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()
-
-At the same time, there maybe a request to access another path, which
-cause both read and write occured.
---
-
-* lib/memfs: fix NewNode if node is symlink to directory
-+
---
-Previously, if a symlink point to directory the memfs NewNode function
-will return an error,
-
- AddChild wui: NewNode: read x/y: is a directory
-
-which cause the files inside y cannot be scanned (404).
-
-This commit fix this issue by checking if the original node mode is a
-directory and return immediately.
---
-
-[#v0_30_0_enhancements]
-=== Enhancements
-
-* lib/memfs: check error on File Close on GoGenerate
-+
---
-Previously, we ignore the error for call to Close when there is an
-error in previous operation.
-
-This changes check the error returned from Close and add it to the
-returned error message.
-
-While at it, use consisten prefix for all returned error:
-"MemFS.GoGenerate".
---
-
-* lib/http: support server caching file system using ETag
-+
---
-If the Server handle file system using MemFS, server will set the
-ETag [1] header using the file epoch as value.
-
-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.
-
-[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
---
-
-* lib/xmlrpc: convert the value using Sprintf on GetFieldAsString
-+
---
-Previously, the GetFieldAsString will return empty string if the
-Value type is not string.
-
-In this commit, we force the value to be string by converted it using
-fmt.Sprintf.
---
-
-* math/big: add some examples of Rat.Int64() and RoundToNearestAway
-
-[#v0_30_0_chores]
-=== Chores
-
-* github: update the Go version to v1.17.1
-
-* lib/strings: update comment and example of TrimAlnum
-
-
-[#v0_29_2]
-== share v0.29.2 (2021-09-06)
-
-[#v0_29_2_bug_fixes]
-=== Bug fixes
-
-* os/exec: fix escaped quote inside the same quote
-+
---
-Shell quote is a hell of complex. For example, one can write
-shell that execute command that contains quote of quote,
-
- sh -c "psql -c 'CREATE ... IDENTIFIED BY PASSWORD '\''pass'\'''"
-
-or to simplify,
-
- sh -c "psql -c \"CREATE ... IDENTIFIED BY PASSWORD 'pass'\""
---
-
-* lib/memfs: fix empty ContentType if MaxFileSize is negative
-+
-A negative MaxFileSize means the content of file will not be mapped to
-memory, but the content type should be detected for other operation.
-
-* lib/memfs: fix empty file not being added to tree
-+
---
-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.
-
-This commit fix this issue by checking for zero file size and for
-io.EOF when reading the file content.
---
-
-* lib/memfs: fix symbolic link with different name
-+
---
-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
-
- parentpath/filename: no such file or directory
-
-because we use the original file name, not the symlinked file name.
-
-This commit fix this issue by not replacing the original FileInfo for
-symlink but by setting only the size and mode.
---
-
-* lib/sql: do not run migration if the last file not exist on the list
-+
---
-Previously, if the last migrated file name not found on the migration
-directory, we start executing migration start from the first file.
-
-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.
---
-
-* lib/http: fix missing content type for XML Header
-+
-If the Endpoint set the RequestType to RequestTypeXML, the response
-header should be set to ContentTypeXML.
-
-* lib/xmlrpc: fix missing port on NewClient
-+
---
-Calling net.Dial or tls.Dial on host without port will cause the
-following error,
-
- NewClient: Dial: dial tcp: address 10.148.0.164: missing port in address
-
-This changes fix this by always generate new host value using previous
-host and port values.
---
-
-* lib/smtp: return io.EOF if no data received from server
-+
-This is to prevent the recv return nil on *Response without an error,
-which may cause panic on caller side.
-
-* os/exec: check for escaped backslash when ParseCommandArgs
-+
-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.
-
-[#v0_29_2_enhancements]
-=== Enhancements
-
-* lib/memfs: set default content type for empty file to "text/plain"
-+
-An empty file should be able to be displayed as text file instead of
-downloaded as binary.
-
-* lib/memfs: change the MarshalJSON to always return an object
-+
---
-Previously, MarshalJSON on memfs will return an object of map
-of all PathNodes and on Node it will return an object.
-
-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.
-
-While at it, use single "mod_time" with value is epoch and return
-the node ContentType as "content_type".
---
-
-* lib/mlog: implement io.Writer and add function ErrorWriter
-+
---
-The ErrorWriter will return the internal default MultiLogger.
-A call to Write() on returned io.Writer will forward it to all registered
-error writers.
-
-A Write method on MultiLogger write the b to all error writers.
-It will always return the length of b without an error.
---
-
-* lib/memfs: add method Save and Encode
-+
-The Save method will write the new content to file system and update
-the content of Node using Encode().
-
-* lib/ssh: add method to set session output and error
-+
---
-Previously, all of the SSH output and error goes to os.Stdout and
-os.Stderr.
-
-This changes add method SetSessionOutputError to change the output and
-error for future remote execution.
---
-
-[#v0_29_2_chores]
-=== Chores
-
-* lib/reflect: make the IsNil tests to become an example
-+
---
-In this way we do test and provide an example at the same time.
-
-While at it, add another test cases for boolean, initialized slice, map,
-and errors.
---
-
-* lib/websocket: try to fix flaky test on client
-+
---
-The following error thrown when running on Github Action using
-Ubuntu-latest and Go 1.16.3,
-
- client_test.go:472: write tcp 127.0.0.1:34460->127.0.0.1:9001:
- write: connection reset by peer
-
-This may be caused by using the same client connection on all test
-cases.
-
-We try to fix this by creating new client on each test cases.
---
-
-
-[#v0_29_1]
-== share v0.29.1 (2021-08-06)
-
-Revert the "lib/errors: return the internal error only if its not nil on
-Unwrap".
-
-Returning instance of e on Unwrap will cause recursive call.
-
-The correct solution to convert an error to errors.E is by implementing the As
-method.
-
-
-[#v0_29_0]
-== share v0.29.0 (2021-08-06)
-
-[#v0_29_0_new_feature]
-=== New feature
-
-ssh/sftp: new package that implement SSH File Transport Protocol v3
-
-The sftp package extend the golang.org/x/crypto/ssh package by
-implementing "sftp" subsystem using the ssh.Client connection.
-
-[#v0_29_0_breaking_changes]
-=== Breaking changes
-
-* text/diff: add functions to compare raw bytes as text and text.Lines
-+
---
-This changes refactoring some functions, notably,
-
-* Rename Bytes function to IsEqual
-* Rename Lines function to Bytes
-* Add function Text that compare two text (raw bytes)
-* Add function Lines that compare two instances of text.Lines
---
-
-[#v0_29_0_enhancements]
-=== Enhancements
-
-* lib/mlog: add function and method Panicf
-+
-The Panicf method is equal to Errf followed by panic. This signature
-follow the log.Panicf convention.
-
-* lib/text: implement function to parse raw bytes into Lines
-
-* lib/text: implement Stringer on Chunk and Line types
-
-* lib/memfs: implement json.Marshaler on MemFS and Node
-+
---
-Previously, without MarshalJSON, encoding the MemFS or Node object will
-result in incomplete information, for example, missing name, modification
-time, and size.
-
-This commit implement the json.Marshaler in MemFS which encode the
-PathNode sorted by keys in ascending order.
---
-
-* lib/bytes: print the ASCII character on the right side on PrintHex
-+
---
-Previously, PrintHex only print the hex value of all bytes with
-specified length.
-
-This changes also print any printables ASCII characters (char 33 through
-126) in the right side column to view readable contents.
---
-
-* lib/totp: lib/totp: increase the maximum steps back on Verify from 2 to 20
-+
-The value 20 means the Verify will check maximum 20 TOTP tokens or 10
-minutes to the past.
-
-* lib/http: check request path as HTML file on getFSNode
-+
---
-Previously, if the request path is not exist we check if request
-contains index.html and if still not exist we return nil.
-
-This commit add another check by appending ".html" to the request path.
-
-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".
---
-
-[#v0_29_0_bug_fixes]
-=== Bug fix
-
-* lib/errors: return the internal error only if its not nil on Unwrap
-+
-If the internal error is nil, the Unwrap method will return the instance
-of e itself.
-
-
-[#v0_28_0]
-== share v0.28.0 (2021-07-06)
-
-[#v0_28_0_breaking_changes]
-=== Breaking changes
-
-* lib/ssh: rename method Get to ScpGet and Put to ScpPut
-+
---
-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.
-
-While at it, use consistent log prefix for error message.
---
-
-* ssh: rename the NewClient function to NewClientFromConfig
-+
-This is to differentiate it with x/crypto ssh package that have the same
-function name.
-
-* ssh: move the config parser to subpackage "config"
-+
-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.
-
-* http: remove the Memfs field from Server
-+
-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.
-
-[#v0_28_0_enhancements]
-=== Enhancements
-
-* websocket: export the Options field on the Server
-+
---
-Previously, the Options field is not exported to prevent user from
-changing it once it set through NewServer() function.
-
-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.
---
-
-* http: export the Options field on the Server
-+
---
-Previously, the Options field is not exported to prevent user from
-changing it once it set through NewServer() function.
-
-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.
---
-
-* websocket: store all the handshake headers to Handshake.Header
-+
---
-Previously only non-required headers are stored in the Handshake Header
-field, while the required header value stored on their respective fields.
-
-This commit store all request header key and values into the Header field.
---
-
-[#v0_27_0]
-== share v0.27.0 (2021-06-05)
-
-This release bring better functionalities, usability, and fixes for `xmlrpc`
-package.
-
-[#v0_27_0_breaking_changes]
-=== Breaking changes
-
-* xmlrpc: change the Response to embed the errors.E
-+
-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.
-
-* xmlrpc: write the XML header when marshaling request not on client
-+
---
-Previously, the XML header is added when sending the request using
-client.
-
-This commit changes it to write the header when marshaling the Request
-instance.
---
-
-* xmlrpc: replace Value field for struct with map of string and value
-+
---
-Previously, for param with type "struct" is represented by slice of
-Member{Name,Value}.
-
-This commit changes the Value field for "struct" to a map of string and
-value for easily access the struct's member, without looping.
---
-
-* xmlrpc: refactoring the parser for decoding XML-RPC request
-+
---
-This changes,
-
-* method to parse XML-RPC request,
-* change the Member field Value type to pointer to Value,
-* change the Request field Params type to slice of pointer of Value,
-* change the Response field Param type to pointer to Value,
-* rename the Value fields from Members to StructMembers and Values to
- ArrayValues
---
-
-[#v0_27_0_new_features]
-=== New features
-
-* memfs: add function to Merge one or more instance of MemFS
-+
---
-The Merge function merge one or more instance of MemFS into single MemFS
-instance.
-
-If there are two instance of Node that have the same path, the last
-instance will be ignored.
---
-
-* xmlrpc: add method to marshal Response
-
-* mlog: add function and method PrintStack
-+
-The PrintStack function or method will writes to error writers the stack
-trace returned by debug.Stack.
-
-[#v0_27_0_enhancements]
-=== Enhancements
-
-* http: add request type for XML
-+
-Setting Endpoint's RequestType to RequestTypeXML will check the content
-type of HTTP request to match with "text/xml".
-
-[#v0_27_0_bug_fixes]
-=== Bug fixes
-
-* memfs: set the field Parent on Node AddChild
-
-* xmlrpc: convert the uint8 and uint16 as type Integer, and Uint as Double
-+
-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.
-
-* xmlrpc: set client response IsFault when StatusCode >= 400
-+
-Previously, we set IsFault to true if the HTTP response code not equal to
-200 only, which is not always correct.
-+
-This commit changes it to check any status code that is greater or equal
-to 400.
-
-* memfs: fix test by checking multiple content-types
-+
-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".
-
-
-[#v0_26_0]
-== share v0.26.0 (2021-05-03)
-
-[#v0_26_0_new_features]
-=== New features
-
-* math/big: add method Add, IsLess, IsGreater, and Scan on Int
-+
-The Add method simplify addition of one value to current Int.
-+
-The IsLess and IsGreater method simplify comparing Int with any value.
-+
-The Scan method allow the Int to be used on sql Scan().
-
-* math/big: add method IsZero on Int
-+
-The IsZero method will return true if the current i value is zero.
-
-* big: extends the standard big.Int
-+
-The standard big.Int does not implement sql/driver.Valuer interface,
-which make it not usable when querying or doing update/insert with
-database.
-+
-This commit extend the big.Int and simplify creating new Int from any
-values using NewInt().
-+
-Also, make it support marshal/unmarshal JSON
-
-[#v0_26_0_enhancements]
-=== Enhancements
-
-* sql: make the column filename on table _migration as primary key
-+
-This will allow deleting the record by filename instead of requiring
-all columns.
-
-* http: add the Total field to EndpointResponse
-+
-The Total field contains the total number of all records, while the
-Count fields only contains the total number of records in Data.
-
-* http: add field Page to EndpointResponse
-+
-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.
-+
-While at it, move the field comment to its declaration.
-
-* big: allow creating new Rat from uint64 and *big.Int
-
-* ssh: check for empty private key file on Get and Put
-+
-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.
-
-[#v0_26_0_chores]
-=== Chores
-
-* memfs: update the test ContentType for JavaScript files
-+
-The latest Go set the content type for JavaScript file as
-"text/javascript; charset=utf-8", not "application/javascript".
-
-* paseto: replace le64() function with binary.Write()
-+
-The le64() return the string representation of uint64 in little endian,
-which is basically binary.Write with parameter output buffer,
-LittleEndian, and input value.
-
-
-[#v0_25_1]
-== share v0.25.1 (2021-04-06)
-
-Set the minimum Go version to 1.16
-
-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.
-
-We choose to move forward.
-
-
-[#v0_25_0]
-== share v0.25.0 (2021-04-06)
-
-[#v0_25_0_breaking_changes]
-=== Breaking changes
-
-* all: refactoring the test.Assert and test.AssertBench signature
-+
-Previously, the test.Assert and test.AssertBench functions has the
-boolean parameter to print the stack trace of test in case its not equal.
-+
-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.
-
-* all: refactoring http.Client methods signature
-+
---
-Previously, parameters to method Delete, Get, Post, PostForm, PostFormData,
-PostJSON, Put, and PutJSON are in the following order:
-
- (headers, path, params)
-
-This is sometimes confusing. To make it better and works with format
-of HTTP request header,
-
-----
-METHOD PATH
-HEADERS
-
-PARAMS
-----
-
-we move the path to the first parameter and headers as the second
-parameter, so the call to client methods would be
-
- (path, headers, params)
---
-
-* http: remove parameter contentType on Client method Put
-+
-Since one can set the Content-Type in parameter headers, this parameter is
-become redundant.
-
-[#v0_25_0_new_features]
-=== New features
-
-* http: add method to generate standard HTTP request on Client
-+
---
-The GenerateHttpRequest method generate http.Request instance from
-method, path, requestType, headers, and params.
-
-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.
-
-For HTTP method is PATCH, POST, or PUT; the params will converted based on
-requestType rules below,
-
-* If requestType is RequestTypeQuery and params is url.Values it will be
- added as query parameters in the path.
-
-* If requestType is RequestTypeForm and params is url.Values it will be
- added as URL encoded in the body.
-
-* If requestType is RequestTypeMultipartForm and params type is
- map[string][]byte, then it will be converted as multipart form in the
- body.
-
-* If requestType is RequestTypeJSON and params is not nil, the params will
- be encoded as JSON in body.
---
-
-* ssh: ask for passphrase if private key is encrypted on generateSigners
-+
-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().
-+
-This changes also remove call to generateSigners on postConfig(),
-instead invoke it from NewClient() to minimize multiple calls to
-generateSigners().
-
-* ssh: use the SSH agent to authenticate on NewClient
-+
-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.
-+
-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.
-+
-This method need manual key added by user to SSH agent before calling
-NewClient to make it works.
-
-[#v0_25_0_enhancements]
-=== Enhancements
-
-* xmlrpc: add debug statements to print request and response
-+
-The debug level is set minimum to 3. If its set it will print the
-request and response to standard output.
-
-
-[#v0_24_0]
-== share v0.24.0 (2021-03-06)
-
-[#v0_24_0_breaking_changes]
-=== Breaking changes
-
-* http: add prefix Header to constants AcceptEncoding and ContentEncoding
-+
-Since both of those constants are used only for HTTP header, it could
-be more clear if we prefix it with "Header".
-
-* sql: change the parameter ExtractSQLFields to driver name
-+
-Previously, we use the string as parameter to set the returned place
-holders.
-+
-This commit changes the parameter to the driver name so if the value
-is "postgres" the place holders will be returned as counter, for example
-"$1", "$2", and so on.
-
-* http: rename "GenericResponse" to "EndpointResponse"
-+
-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.
-
-* http: refactoring parameters on Callback and CallbackErrorHandler
-+
-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.
-+
-This changes wrap the three parameters into single type EndpointRequest
-with addition field Endpoint, which contains the registered Endpoint.
-+
-On the CallbackErrorHandler we also have three parameters, but instead
-of request body we have an error.
-+
-This changes store the error for CallbackErrorHandler inside
-EndpointRequest.Error field.
-
-* http: move the CORS options to separate struct
-
-[#v0_24_0_new_features]
-=== New features
-
-* http: add methods IPAddressOfRequest and ParseXForwardedFor
-+
-The IPAddressOfRequest get the client IP address from HTTP request header
-"X-Real-IP" or "X-Forwarded-For" or from Request.RemoteAddr, which ever
-non-empty first.
-+
-The ParseXForwardedFor parse the HTTP header "X-Forwarded-For" value from
-the following format "client, proxy1, proxy2" into client address and
-list of proxy addressess.
-
-* api/slack: create new client for webhook
-+
-Unlike PostWebhook API which is close and open one connection at the
-time, the WebhookClient is keep open.
-+
-Use the WebhookClient for long running program that post message every
-minutes or seconds.
-
-* mlog: implement MultiLogger
-+
---
-MultiLogger represent a single log writer that write to multiple outputs.
-MultiLogger can have zero or more writers for standard output (normal log)
-and zero or more writers for standard error.
-
-The MultiLogger is buffered to minimize waiting time when writing to
-multiple writers that have different latencies.
-For example, if we have one writer to os.Stdout, one writer to file, and
-one writer to network; the writer to network may take more time to finish
-than to os.Stdout and file, which may slowing down the program if we want
-to wait for all writes to finish.
-
-For this reason, do not forget to call Flush when your program exit.
-
-The default MultiLogger use time.RFC3339 as the default time layout, empty
-prefix, os.Stdout for the output writer, and os.Stderr for the error
-writer.
-
-Format of written log,
-
- [time] [prefix] <message>
-
-The time and prefix only printed if its not empty, and the single space is
-added for convenience.
-Unlike standard log package, this package does not add new line to the end
-of message if its not exist.
---
-
-* http: export the HandleFS method
-+
-The HandleFS handle the request as resource in the memory file system.
-This method only works if the Server.Memfs is not nil.
-+
-If the request Path exists in file system, it will return 200 OK with the
-header Content-Type set accordingly to the detected file type and the
-response body set to the content of file.
-If the request Method is HEAD, only the header will be sent back to client.
-+
-If the request Path is not exist it will return 404 Not Found.
-
-* clise: add method Pop
-+
-The Pop method remove the last Push()-ed item and return it to caller.
-It will return nil if no more item inside it.
-
-* ini: add support for marshaling slice of struct
-+
---
-Given a struct with exported field is slice of struct and tagged with
-section and sub-section, the exported field will be marshalled as,
-
- [section "sub"]
- field = value
---
-
-* ini: add support for marshaling pointer to struct and to time.Time
-+
---
-Given the following field struct with tag,
-
- V *T `ini:"sec:sub"
-
-If the V is not nil, it will marshal it into,
-
- [sec "sub"]
- <field name or tag> = <field value>
---
-
-* ini: add support for un-marshaling to struct and slice of struct
-
-* big: add method that implement sql/driver.Valuer for type Rat
-+
-The Rat.Value() return the value as []byte.
-
-[#v0_24_0_enhancements]
-=== Enhancements
-
-* clise: make all methods safe for concurrent use
-
-* http: add fields for paging on GenericResponse
-+
-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.
-+
-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.
-
-[#v0_24_0_bug_fixes]
-=== Bug fixes
-
-* reflect: check using equal statement on IsNil
-+
-Beside using IsNil(), return the last check using "v == nil".
-
-
-[#v0_23_0]
-== share v0.23.0 (2021-02-05)
-
-This release bring major refactoring to package memfs to allow embedding two
-or more directories in single package.
-
-The minimum Go version is increased to 1.14.
-
-[#v0_23_0_breaking_changes]
-=== Breaking changes
-
-* memfs: refactoring, allow multiple instances of memfs in single package
-+
-Previously, the generated Go code from memfs can be used only once
-on the package that use it. For example, if we have two instances of
-memfs.MemFS and both of them call GoGenerate(), when we load them back
-again only the last one will be active and set the global variable
-memfs.GeneratedPathNode.
-+
-This changes refactoring on how we use memfs by storing the
-generated path node into variable that is defined by user and pass
-them to New Options.
-
-* memfs: remove field WithContent
-+
-The field WithContent is not necessary if we set MaxFileSize to negative
-value.
-
-* http: embed the memfs.Options into ServerOptions
-+
-This is to minimize duplicate on fields names and give clear distinction
-between options for Server and options for serving files on memory using
-memfs.
-
-* io: embed the memfs.Options into DirWatcher
-+
-This is to minimize duplicate configuration between DirWatcher and
-memfs, and to allow clear distinction between which options that
-affect the directory tree and options for DirWatcher.
-
-* memfs: allow AddFile to set internal path
-+
-Previously, AddFile set the internal path equal to path of file to be
-included. This may cause conflict if the file is already included
-due to the same sys path but different internal path.
-+
-This commit add parameter internalPath to set custom internal path in
-the memfs map.
-
-* memfs: refactoring Go generate code to use memfs.MemFS instance
-+
-Instead of using memfs.PathNode, which is confusing for new user
-(what is PathNode?), we actually can use memfs.MemFS instance.
-+
-This effect on how we use memfs in http package.
-
-* dns: change the SOA field in ZoneFile to non-pointer
-+
-The reason we use pointer for SOA record is so we can save them only
-if its not nil. A nil SOA record cause the generated JSON become "null"
-and this is make the consumer of ZoneFile do more work, checking for the
-null and initialize it when required.
-+
-This changes, make the SOA record to non-nil and we save the record only
-if the MName field is not empty.
-
-* dns: replace master word with zone
-+
-This is for consistency for type and variable names.
-
-* sql: sort returned names on ExtractSQLFields sorted in ascending
-+
-This is to make sure that any test that use the package always
-predictable.
-+
-While at it, add paramter to change placeholder on ExtractSQLFields.
-
-[#v0_23_0_new_features]
-=== New features
-
-* http: add method Post on client
-+
-The Post method send the POST request to path without setting
-"Content-Type".
-
-* lib/clise: new package that implement circular slice
-+
---
-A circular slice is a slice that have fixed size.
-An append to slice that has reached its length will overwrite and start
-again from index 0.
-
-For example, a clise with size 5,
-
- c := clise.New(5)
- c.Push(1, 2, 3, 4, 5)
- fmt.Printf("%v\n", c.Slice()) // [1 2 3 4 5]
-
-If we push another item, it will overwrite the first index,
-
- c.Push(6)
- fmt.Printf("%v\n", c.Slice()) // [6 2 3 4 5]
-
-See the examples for usage of the package.
---
-
-* time: add function UnixMicro that return UNIX time in micro seconds
-
-* api/slack: simple API for sending message to Slack using only
- standard packages.
-
-* runes: add function to inverse the slice of rune
-+
-The Inverse function reverse the order of slice of rune without
-allocating another slice.
-
-* big: add method Humanize
-+
-The Humanize method return the r as string with custom thousand and
-decimal separator.
-
-* big: add method to round fraction to nearest non-zero value
-+
-The RoundNearestFraction does not require precision parameter, like in
-other rounds function, but it figure it out based on the last non-zero
-value from fraction.
-
-[#v0_23_0_enhancements]
-=== Enhancements
-
-* dns: change the error messages on ResourceRecord initAndInitialize
-+
-This change make the error message more readable and understandable by
-consumer
-
-* dns: add method to get list of non-local caches in the Server
-+
-The CachesLRU method return the list of non-local caches ordered by
-the least recently used.
-+
-This changes affect the answer type which must be exported, including
-most of its fields, so consumer can access it.
-
-[#v0_23_0_bug_fixes]
-=== Bug fixes
-
-* sql: check nil on Migrate parameter "fs" using reflect.IsNil
-+
-If we pass nil pointer of type to fs, the if condition will not true
-and this cause panic because fs is not nil.
-
-* http: fix the package documentation
-+
-The RegisterXxx methods on Server has been replaced with single method,
-RegisterEndpoint.
-
-* dns: fix saving the TXT record file on zone file
-+
-The TXT record value must be wrapped with quote when stored on zone
-file.
-
-
-[#v0_22_0]
-== share v0.22.0 (2021-01-06)
-
-[#v0_22_0_breaking_changes]
-=== Breaking changes
-
-* contact: remove unused package proofn
-
-* sql: change the new client function parameter into struct of options.
-
-[#v0_22_0_new_features]
-=== New features
-
-* cmd: add new CLI "totp"
-+
-The totp is a program to generate Time-based One-time Password from
-secret key.
-
-* totp: add method to generate n number of passwords
-
-[#v0_22_0_enhancements]
-=== Enhancements
-
-* http: print client request if debug value is equal or greater than 2.
-+
-If user set DEBUG environment variable or debug.Value to 2 or greater,
-the http Client will print the request (header and body) to the
-standard output.
-
-* ssh: print the private key file that has an error when generating signers
-
-
-[#v0_21_0]
-== share v0.21.0 (2020-12-06)
-
-[#v0_21_0_breaking_changes]
-=== Breaking changes
-
-* test: refactoring Assert with better error message
-+
-The new Assert function use the reflect.DoEqual that return an error
-which describe which field have unmatched value.
-
-[#v0_21_0_new_features]
-=== New features
-
-* http: allow Endpoint to register custom error handler
-+
-The new field ErrorHandler on Endpoint allow the implementor to define
-their own function to handler error from Endpoint.Call.
-+
-If the ErrorHandler is nil it will default to DefaultErrorHandler.
-
-* totp: new package that implement TOTP protocol
-+
-Package totp implement Time-Based One-Time Password Algorithm based on
-RFC 6238.
-
-[#v0_21_0_bug_fixes]
-=== Bug fixes
-
-* parser: fix Line method that always return non-empty line
-+
-In case of content end without new line, for example "a\nb", the Line()
-method always return "b, 0" on the last line.
-
-* smtp: update the expired test certificate
-
-* websocket: create buffered channel for running queue.
-+
-This is to fix Stop() method waiting for running channel to be consumed.
-
-[#v0_21_0_enhancements]
-=== Enhancements
-
-* big: update the latest expected error message with Go tip
-
-* http: add an example on how to write custom HTTP status code
-+
-The example show how to use http.ResponseWriter.WriteHeader to write
-custom HTTP status code instead of relying on errors.E.
-
-* net: always return the host name or IP on ParseIPPort.
-+
-Previously, if the address is an IP address the returned value is empty,
-for example "127.0.0.1" will return empty host but with non-nil IP and
-port.
-+
-This changes always return the host either as host name (the same as
-paremeter) or valid IP address.
-
-[#v0_21_0_chores]
-=== Chores
-
-* all: replace the tasks to serve and generate docs using ciigo as library
-+
-This way, one does not need to install ciigo binary, only require Go
-tools.
-
-
-[#v0_20_1]
-== share v0.20.1 (2020-11-08)
-
-[#v0_20_1_bug_fixes]
-=== Bug fixes
-
-* websocket: set TLSConfig to nil if Endpoint scheme is not https or wss.
-+
-If user set TLSConfig but the Endpoint is not start with "https" or "wss",
-client open() method may return an error "Connect: tls: first record does
-not look like a TLS handshake".
-
-* paseto: add 5 seconds time drift when validating JSONToken
-
-[#v0_20_1_enhancements]
-=== Enhancements
-
-* big: add method RoundToNearestAway and RoundToZero
-+
-RoundToNearestAway round r to n digit precision using nearest away mode,
-where mantissa is accumulated by the last digit after precision.
-For example, using 2 digit precision, 0.555 would become 0.56.
-+
-RoundToZero round r to n digit precision using to zero mode.
-For example, using 2 digit precision, 0.555 would become 0.55.
-
-* parser: add Stop method
-+
-The Stop method return the remaining unparsed content and its last
-position, and then call Close to reset the internal state back to zero.
-
-[#v0_20_1_chores]
-=== Chores
-
-* paseto: fix linter warnings
-
-
-[#v0_20_0]
-== share v0.20.0 (2020-10-05)
-
-[#v0_20_0_new_features]
-=== New features
-
-* lib/paseto: a simple, ready to use, implementation of Platform-Agnostic
- SEcurity TOkens
-+
-This implementation only support PASETO Protocol v2.
-+
-This library focus on how to sign and verify data, everything else is
-handled and filled automatically.
-
-[#v0_20_0_enhancements]
-=== Enhancements
-
-* dns: serve DoT without SSL if server is behind proxy or tlsConfig is null.
-+
-Previously we only check for tlsConfig, if its null the DoT server
-will not running.
-There is a use case where the SSL terminated by proxy and the connection
-is forwarded to DNS server, so this changes accommodated it.
-
-* http: increase the debug level from 2 to 3
-
-
-[#v0_19_0]
-== share v0.19.0 (2020-09-08)
-
-[#v0_19_0_breaking_changes]
-=== Breaking changes
-
-* dns: unexport the Messsage's Packet field
-
-* dns: change the HostsFile Messages to list of ResourceRecord
-
-* dns: unexport the master file path field
-
-* dns: refactoring the ResourceRecord values from []byte to string
-+
-There are two reasons for this changes. First, to allow JSON encoded
-of ResourceRecord.Value without encoded to base64.
-+
-Second, to minimize unreleased packet due to the backing storage is
-still used when assigned to Value (or any []byte field in RDataXXX).
-
-* dns: dns: split between MasterFile and masterParser
-+
-While at it add field Records that contains unpacked ResourceRecord as
-mapping between domain and ResourceRecord.
-+
-This is useful for client that need to edit the RR in MasterFile.
-+
-This changes also unexport the Messages field, to access it use the method
-Messages.
-
-* websocket: move the server handler to ServerOptions
-
-[#v0_19_0_new_features]
-=== New features
-
-* dns: add method to remove local caches by names on Server
-
-* dns: add method to search caches
-
-* dns: add method Delete to MasterFile
-
-* dns: add method to remove RR from cache and master file
-
-* dns: add method to save the master records to file
-
-* dns: implement method to add new RR to master file
-
-* dns: add method to update/insert resource record to caches
-
-* dns: add method to initialize and validate ResourceRecord
-
-* websocket: add server options to change the connect and status paths
-+
-Previously, there is only one option for server, the port where it will
-listen.
-+
-This changes add option to change the connect path (default to "/"
-previously) and new path and handler for retrieving server status.
-
-[#v0_19_0_bug_fixes]
-=== Bug fixes
-
-* dns: fix parsing SOA resource record data from master file
-
-* dns: stop all forwarders on Stop()
-
-* http: write the HTTP status code after setting content-type on error
-
-* ini: ignore the last empty line on unsetAll
-
-
-[#v0_18_0]
-== share v0.18.0 (2020-08-06)
-
-[#v0_18_0_breaking_changes]
-=== Breaking changes
-
-* big: add global flag MarshalJSONAsString
-+
-MarshalJSONAsString define the default return behaviour of MarshalJSON().
-If its true (the default) the returned JSON format will encapsulated in
-double quote, as string instead of as numeric.
-
-* dns: refactoring resource record fields
-
-* http: do not return error based on response code
-+
-The error in doRequest should be about connection error, everything
-else should be handled by user.
-
-* http: allow setting response type when registering PUT
-+
-User of this library may want to return something and they will suprised
-if the library always set the response type to None.
-
-[#v0_18_0_bug_fixes]
-=== Bug fixes
-
-* http: fix panic if Request.Form is not initialized on Endpoint.call
-
-[#v0_18_0_enhancements]
-=== Enhancements
-
-* dns: add method to create Message from hostname and list of addresses
-
-* dns: add method to remove caches by names on Server
-
-* http: add method Put for Client
-
-* http: add method to convert RequestMethod to string
-
-* parser: add method to get single line
-
-* strings: add function to delete a value from slice of string
-
-
-[#v0_17_0]
-== share v0.17.0 (2020-07-05)
-
-[#v0_17_0_breaking_changes]
-=== Breaking changes
-
-* dns: replace RDataText with plain []byte
-
-* http: add parameter headers to client methods
-
-* http: return the http.Response as the first parameter
-
-[#v0_17_0_bug_fixes]
-=== Bug fixes
-
-* http: initialize TLSClientConfig only if insecure is true
-
-* io: truncate file on Copy
-
-* websocket: fix race on pingTicker when stopping server
-
-[#v0_17_0_enhancements]
-=== Enhancements
-
-* http: check for possible index.html file on getFSNode
-
-* http: add method Delete
-
-* http: add method Stop for HTTP server
-
-* http: check the number of bytes written on ResponseWriter.Write
-
-* http: log error if path not exist if debug value is set to 3 or greater
-
-* smtp: check for EOF when receiving data from server
-
-
-[#v0_16_0]
-== share v0.16.0 (2020-06-05)
-
-[#v0_16_0_breaking_changes]
-=== Breaking changes
-
-* dns: refactoring loading hosts and master files
-+
-Instead of as methods in Server, we detach the LoadHostDir and
-LostMasterDir into functions that return list of filename and their
-content.
-
-* dns: disable serving DoH and DoT if port is not set (0)
-+
-Previously, if HTTPPort or TLSPort is not set (0) we set it to default
-value and keep serving the DNS over HTTP and TLS. Sometimes, user may
-want to serve DNS over UDP only.
-+
-This changes disable serving DNS over HTTP (DoH) and TLS (DoT) if port
-is not set, or 0.
-
-* email: rename ParseAddress function to ParseMailboxes
-
-* http: add parameter "insecure" when creating new client
-
-* ini: fix inconsistencies between empty string and boolean true
-+
-In Git specification, an empty variable is equal to boolean true.
-This cause inconsistency between empty string and boolean true.
-
-* memfs: simplify the API, add directory parameter to New
-+
-This changes add parameter directory to be mounted in New(), so user
-did not need to call Mount manually
-+
-This cause the Mount method and its sibling, Unmount and IsMounted
-become unneeded, so we remove them.
-
-[#v0_16_0_bug_fixes]
-=== Bug fixes
-
-* api/telegram/bot: fix request parameter on GetMyCommands
-
-[#v0_16_0_new_features]
-=== New features
-
-* bytes: add function MergeSpaces
-+
-The function MergeSpaces will convert sequences of white space into
-single space ' '.
-
-* email: add methods to unmarshal/marshal Mailbox from/to JSON
-* email: add function to parse single mailbox
-* email: add function to create multipart text and HTML message
-
-* http: support CORS with white list of origin and headers
-
-* ini: add method UnsetAll to remove all variables in section and/or
- subsection that match with the key
-
-* ini: add method to Unmarshal ini values to struct
-
-* os/exec: new package to simplify the standard "os/exec"
-+
-New extension to standard package is function ParseCommandArgs() that
-receive input as string and return itas command and list of arguments.
-Unlike strings.Fields() which only separated the field by space,
-ParseCommandArgs can detect possible single, double, or back quotes.
-+
-Another extension is Run() function that accept the string command
-to be executed and their standard output and error.
-
-* sql: add method to migrate database schema
-+
-The Migrate method migrate the database using list of SQL files inside
-a directory.
-Each SQL file in directory will be executed in alphabetical order based on
-the last state.
-+
-The state of migration will be saved in table "_migration" with the SQL
-file name that has been executed and the timestamp.
-
-[#v0_16_0_enhancements]
-=== Enhancements
-
-* api/telegram/bot: delete webhook upon setting new webhook
-
-* dns: do not load hidden hosts and master file
-+
-Previously, the LoadHostDir and LoadMasterDir load all files inside
-the directory without checking if its hidden (starting with dot) or not.
-+
-This changes make the hidden file not loaded so one can disable it
-temporarily by prefixing it with dot.
-
-* ini: make the add method append the variable after existing same key
-
-* memfs: make the Node Readdir works when calling from generated Go code
-+
---
-Previously, the Go generated code from call to GoGenerate() set only
-mapping of path to node. Calling Readdir() using http.File using
-
- root, err := mfs.Open("/")
- fis, err := root.Readdir(0)
-
-will return nil on fis.
-
-This changes add all child nodes to generated node.
---
-
-* websocket: allow "https" scheme on Client's Endpoint
-
-
-[#v0_15_0]
-== share v0.15.0 (2020-05-04)
-
-[#v0_15_0_breaking_changes]
-=== Breaking changes
-
-* big: check for zero length slice of byte or string on toRat
-* ssh: replace the ClientConfig with ConfigSection
-
-[#v0_15_0_new_features]
-=== New features
-
-* ssh: implement SSH client configuration parser -- ssh_config(5)
-* api/telegram/bot: Go package for Telegram API Bot
-* http: implement a simplified HTTP client
-
-* net/html: new package to simplify the golang.org/x/net/html
-+
-The x/net/html package currently only provide bare raw functionalities
-to iterate tree, there is no check for empty node, no function to
-get attribute by name, and no simple way to iterate tree without looping it
-manually.
-+
-This package extends the package by adding methods to get node's attribute
-by name, get the first non-empty child, get the next non-empty sibling, and
-to iterate each node in the tree from top to bottom.
-
-[#v0_15_0_enhancements]
-=== Enhancements
-
-* big: return "0" instead of "<nil>" on Rat.String()
-* big: return false if Rat is nil on IsGreaterThanZero
-* http: add parameter to set default client's headers
-* websocket: add method to gracefully Close the client connection
-* websocket: add routine that send PING control frame on Connect
-
-[#v0_15_0_bug_fixes]
-=== Bug fixes
-
-* reflect: remove checking for method IsEqual on type reflect.Ptr
-
-
-[#v0_14_0]
-== share v0.14.0 (2020-04-03)
-
-[#v0_14_0_breaking_changes]
-=== Breaking changes
-
-* http: simplify server Endpoint registrations
-+
-Previously, each endpoint with method DELETE, GET, PATCH, POST, and PUT
-require calling different call for registration. This change simplify
-it to one call only, "RegisterEndpoint", and the registration process
-will be handled automatically based on value on field Method.
-
-* mining/math: move the package from "lib/mining/" to "lib/" directory
-
-[#v0_14_0_new_features]
-=== New features
-
-* debug: add a wrapper for starting and stopping CPU profile
-
-* math/big: new package that extends the capabilities of "math/big"
-+
-The "big" package add custom global precision, rounding mode, and number
-of digit precision after decimal point for all instance of Float that
-use the package.
-
-* reflect: new package that extends the standard reflect
-+
-This package add new interface "Equaler", it is an interface that
-have single method "IsEqual()".
-+
-Also, we have new function "IsNil(interface{})" that will return true
-if the value in interface{} is nil.
-
-* strings: add function SingleSpace
-+
-The SingleSpace function convert all sequences of white spaces into
-single space ' '.
-
-[#v0_14_0_enhancements]
-=== Enhancements
-
-* http: embed the standard http package instead of separate field
-
-* hunspell: return the stem instead of root word on Spell() method
-
-* hunspell: add Stem() method to Spell and Stem
-+
-The Stem() method reduce inflected (or sometimes derived) words to
-their word stem, base, or root form.
-
-* hunspell: add Analyze() method to Spell and Stem
-+
-The Analyze() method will return list of morphological fields of the
-word.
-
-* strings: check for other white spaces on MergeSpaces
-
-[#v0_14_0_bug_fixes]
-=== Bug fixes
-
-* http: fix the content-length header not set if file is not cached
-
-
-[#v0_13_0]
-== share v0.13.0 (2020-03-11)
-
-[#v0_13_0_breaking_changes]
-=== Breaking changes
-
-Set the minimum Go version to 1.13.
-
-[#v0_13_0_new_features]
-=== New features
-
-* hunspell: a library to parse the Hunspell file format
-* parser: provide a common text parser, using delimiters
-
-[#v0_13_0_enhancements]
-=== Enhancements
-
-* dns: use net.Addr for primary and fallback UDP/tCP addresses
-* dns: change the mark of input/output in log output
-* io: add function to copy file
-* time: add functions to get Unix time in milliseconds (int64 and string)
-* websocket: allow custom TLS configuration on client
-
-[#v0_13_0_bug_fixes]
-=== Bug fixes
-
-* dns: fix handling server without fallback forwarder
-* dns: check for nil DNS-over-TLS server on server's Stop
-
-
-[#v0_12_0]
-== share v0.12.0 (2020-02-13)
-
-[#v0_12_0_breaking_changes]
-=== Breaking changes
-
-* bytes: move function JSONEscape and JSONUnescape to package json
-* strings: move JSONEscape and JSONUnescape to package json
-* time: change the Microsecond return type from int to int64
-* websocket: change the RouteHandler signature to return Response
-
-[#v0_12_0_new_features]
-=== New features
-
-* json: new packages to work with JSON
-* sql: a new package as an extension to "database/sql"
-* xmlrpc: new package for working with XML-RPC
-
-[#v0_12_0_enhancements]
-=== Enhancements
-
-* strings: add function to reverse a string
-
-[#v0_12_0_bug_fixes]
-=== Bug fixes
-
-* dns: fix index out of range when unpacking OPT RR
-
-
-[#v0_11_0]
-== share v0.11.0 (2019-12-26)
-
-[#v0_11_0_breaking_changes]
-=== Breaking changes
-
-* dns: merge Start and Wait into ListenAndServe
-
-[#v0_11_0_new_features]
-=== New features
-
-* memfs: implement http.FileSystem on MemFS
-* memfs: implement http.File on Node
-* memfs: implement os.FileInfo on Node
-* memfs: implement io.Closer, io.Reader, and io.Seeker on Node
-
-[#v0_11_0_enhancements]
-=== Enhancements
-
-* dns: allocate raw packet on receive
-* dns: log the number of pruned records
-* errors: add field Name and err
-
-[#v0_11_0_bug_fixes]
-=== Bug fixes
-
-* dns: split between read and write timeout for TCPClient
-
-
-[#v0_10_2]
-== share v0.10.2 (2019-12-07)
-
-[#v0_10_2_bug_fixes]
-=== Bug fixes
-
-* dns: check for bad certificate when reading DoT request
-* dns: fix the use of goroutine on runForwarders
-
-
-[#v0_10_1]
-== share v0.10.1 (2019-12-05)
-
-[#v0_10_1_bug_fixes]
-=== Bug fixes
-
-* dns: close the connection if receiving zero packet on serveTCPClient
-* dns: increase and decrease number of forwarders only for primary forwarders
-* dns: make the stopper channel to be buffered
-* dns: check for nil forwarder
-* dns: check for nil connection on DoTClient's Close
-* dns: check for zero query type and class on TCPClient Lookup method
-* dns: check for nil connection on Close at TCPClient
-* dns: minimize double looping on checking error at serveTCPClient
-* git: fix the test using full path URL and repository directory
-* io: fix test using existing file instead of generate file
-* net: handle interrupted system call on epoll Wait
-* ssh: fix test ClientConfig initialize on Github Actions
-* websocket: remove test for empty endpoint due to different format
-* websocket: fix zero response ID when error on handleText
-
-[#v0_10_1_enhancements]
-=== Enhancements
-
-* dns: remove the use of pointer on Message fields
-* dns: remove the use of ResourceRecord pool
-* http: add method HTTPMethod to Endpoint
-* http: disable creating Memfs if Root options is empty
-* memfs: remove unneeded call to GeneratedPathNode.Set
-* mining: move commands to root
-* websocket: add examples of WebSocket as chat server and client
-* websocket: add new function to create broadcast response
-* websocket: add field Conn to represent connection in Request
-* websocket: check for read timeout on recv
-* websocket: remove unused error on NewServer
-
-[#v0_10_0]
-== share v0.10.0 (2019-11-05)
-
-[#v0_10_0_new_features]
-=== New features
-
-* dns: implement client and server for DNS over TLS
-* ini: add method GetsUniq and ValsUniq that return uniq values only
-* net: implement network polling using epoll and kqueue
-
-[#v0_10_0_breaking_changes]
-=== Breaking Changes
-
-* dns: change the server certificate options to load from files
-* ini: change Gets return as is, with duplicate values
-
-[#v0_10_0_enhancements]
-=== Enhancements
-
-* dns: allow listening on DoH without requiring certificate
-* ini: support marshaling and un-marshaling time.Duration
-* ini: support marshaling and un-marshaling time.Time
-* ini: support marshaling and un-marshaling embedded structs
-* websocket: websocket: replace epoll implementation with libnet.Poll
-
-[#v0_10_0_bug_fixes]
-=== Bug fixes
-
-* dns: return error code 4 if server receive unknown message class or type
-* dns: return an error if section question contains invalid packet
-* ini: fix return value for empty string in IsValueBoolTrue
-* strings: fix logic of Split function
-* websocket: set the response ID after calling handler on handleText
-* websocket: wrap the response with frame on sendResponse
-
-
-[#v0_9_0]
-== share v0.9.0 (2019-10-08)
-
-[#v0_9_0_new_features]
-=== New features
-
-* bytes: add function to get all indexes of word in string
-* bytes: add function to take snippets from string by indexes
-* bytes: add function to get all indexes of token in string
-* ints: add function to merge two slices by distance
-* memfs: add method to add file directly as child of root
-* memfs: add method to Search content of files
-* sanitize: new package to sanitize markup document into plain text
-+
-Current implementation have a function to sanitize the content of HTML.
-
-* strings: add function to convert slice of string to slice of slice of bytes
-
-* http: implement key binding in registered Endpoint's Path
-+
-Previously, only raw path can be registered on Endpoint. This changes
-implement key binding using colon ":" on path. For example, registering
-path "/:x/y" will bind key "x" to a string value that can be accessed on
-http.Request.Form using Get method.
-
-[#v0_9_0_breaking_changes]
-=== Breaking Changes
-
-* ini: set variable with "=" without a value default to empty string
-+
---
-Previously, a variable end with "=" will have value set to "true".
-For example,
-
-----
-[section]
-var =
-----
-
-set the "var" value to string "true".
-
-This changes make the variable that end with "=" without any value
-to be an empty string, so "var" value is equal to "".
---
-
-[#v0_9_0_bug_fixes]
-=== Bug fixes
-
-* ini: check for possible nil variable on Write
-
-* dns: allow message with non recursive-desired to be forwarded
-+
-On macOS, turn out, all DNS queries have RD flag set to zero. This cause
-no DNS queries forwarded to parent server.
-
-[#v0_9_0_enhancements]
-=== Enhancements
-
-* http: export the Memfs field on Server
-+
-User of HTTP can use the Memfs field to get the content manually or
-to Search the content.
-
-* http: add content and response type HTML and XML
-
-* memfs: export the Decode method on Node
-
-
-[#v0_8_2]
-== share v0.8.2 (2019-09-05)
-
-[#v0_8_2_enhancements]
-=== Enhancements
-
-* http: make the request body always available even after ParseForm()
-+
-Previously, if the request type is query, form, or JSON, we call the
-ParseForm() to let the http.Request read the Body POST form data and fill
-the Form and/or PostForm fields. This method will cause the request
-Body will become empty since its already read and closed.
-One of use case of POST with form data is to check the integrity of POST
-body using checksum, which is not possible using only ParseForm().
-This commit read all the body first into reqBody and recreate the request
-Body back using ioutil.NopCloser and bytes.Buffer.
-
-* all: replace document generator from asciidoctor to ciigo
-+
-Previously, generating HTML files from asciidoc files require installing
-ruby, asciidoctor, and its dependency through Gemfile.
-To simplify this, we replace it with ciigo. Ciigo not only can convert
-the asciidoc files but it also support serving the file inside HTTP
-server and watching changes on asciidoc files during development for
-local previewing.
-
-* memfs: log and ignore error from NewNode
-+
-An error for calling NewNode should not stop processing all files
-in directory.
-
-* io: log and ignore error from NewNode
-+
-An error for calling NewNode should not stop processing all files
-in directory.
-
-
-[#v0_8_1]
-== share v0.8.1 (2019-08-05)
-
-[#v0_8_1_enhancements]
-=== Enhancements
-
-* lib/ini: add functions to marshal/unmarshal bytes from/to struct.
-+
-The format to marshal/unmarshal ini stream is behave like JSON.
-
-* lib/memfs: add method to encode the content of file.
-+
-The ContentEncode() method encode each node's content into specific
-encoding, in other words this method can be used to compress the content
-of file in memory before being served or written.
-Only file with size greater than 0 will be encoded.
-List of known encoding is "gzip".
-
-* lib/memfs: ignore generated output filename on GoGenerate
-+
-In case the user Mount() the directory that include the generated output
-file, we want that file to be excluded from .go static source.
-
-* lib/memfs: set the Node Size to be zero if node is directory
-
-
-[#v0_8_0]
-== share v0.8.0 (2019-07-09)
-
-[#v0_8_0_breaking_changes]
-=== Breaking changes
-
-* All ASCII related contants and functions now being moved from `bytes`
- package to `ascii` package.
-
-[#v0_8_0_new_features]
-=== New features
-
-* ascii: new library for working with ASCII characters
-
-[#v0_8_0_enhancements]
-=== Enhancements
-
-* dns: add method to restart forwarders
-* dns: add fallback nameservers
-* ini: create new section or variable if not exist on Set
-
-
-[#v0_7_0]
-== share v0.7.0 (2019-06-14)
-
-This release bring major refactoring on `ini` package to provide a clean and
-simple API.
-
-[#v0_7_0_breaking_changes]
-=== Breaking Changes
-
-* ini: major refactoring
-* net: add parameter to check Fully Qualified Domain Name on IsHostnameValid
-
-[#v0_7_0_new_features]
-=== New features
-
-* spf: implementation of Sender Policy Framework (RFC 7208)
-* ssh: package ssh provide a wrapper to golang.org/x/crypto/ssh
-
-[#v0_7_0_enhancements]
-=== Enhancements
-
-* dns: add function to lookup PTR record by IP address
-* dns: export Lookup method as part of Client interface
-* doc: regenerate to use new style
-* http: print the not-found path on Server's getFSNode()
-* ini: add method Vars that return all variables as map
-* ini: add method to Rebase other INI object
-* ini: add method to add, set, and unset variable
-* ini: add method to convert key-value to map
-* ini: add method to get section object by section and/or subsection name
-* ini: add method to get variable values as slice of string
-* ini: add method to prune INI variables
-* ini: add methods to support templating
-* io: add function to check if content of file is binary
-* net: add function to check if IP address is IPv4 or IPv6
-* net: add function to convert IPv6 into dot format
-* ns: set log flag to 0, without time prefix
-* strings: add function to append uniq values to slice of strings
-
-[#v0_7_0_bug_fixes]
-=== Bug fixes
-
-* io: watch changes on sub of sub directories on DirWatcher
-* dns: substract the message TTL when the answer found on cache
-* dns: always return true when answers RR exist and no TTL is zero
-
-
-[#v0_6_1]
-== share v0.6.1 (2019-05-11)
-
-* `memfs`:
-** fix empty list names from MemFS created from GeneratedPathNode
-** set root if GeneratedPathNode is not empty
-** sort the generated file names
-** fix template when generating empty content
-
-
-[#v0_6_0]
-== share v0.6.0 (2019-05-07)
-
-This release bring major changes on dns package.
-Most notable changes are adding caches and query forwarding (recursion), and
-removing the server handler.
-
-[#v0_6_0_breaking_changes]
-=== Breaking Changes
-
-* `dns`:
-** refactor server to use Start(), Wait(), and Stop()
-** use direct certificate instance on ServerOptions
-** rename Send to Write, and change the parameter type to slice of byte
-** remove "elapsed" parameter on Message.IsExpired()
-** unexport the Request type
-** remove receiver interface
-** unexport connection type
-** remove unused address parameter on client's Query()
-** unexport all fields from UDP and TCP clients
-** remove TCPPort on ServerOptions
-
-* `http`:
-** change server initialization using options
-
-* `io`:
-** simplify Watcher to use callback instead of channel
-
-* `memfs`:
-** refactoring go generate file to use type from memfs
-
-[#v0_6_0_new_features]
-=== New features
-
-* `crypto`: new package that provide a wrapper for standard crypto library
-
-* `dns`:
-** add caches to server
-** add method to set AA, Query, RD, RCode on Message
-** add mapping of response code to human readable names
-** implement recursion, forwarding request to parent name servers
-** check for zero TTL on authorities and additionals RR on IsExpired
-
-* `io`:
-** implement naive directory change notification, DirWatcher
-
-* `memfs`:
-** add parameter to make reading file content become optional
-** add method to unmount directory
-** add method to check if memfs contains mounted directory
-** add method to update node content and information
-** export the method to add new child
-** add method to remove child from any node
-
-* `smtp`: add field DKIMOptions to Domain
-
-[#v0_6_0_bug_fixes]
-=== Bug fixes
-
-* `dns`:
-** fix data race issue when running test
-** set the TTL offset when packing resource record
-** fix parsing TXT from zone file
-
-* `http`:
-** allow serving directory with slash
-
-* `memfs`:
-** fix possible invalid system path on file with symbolic link
-** refresh the directory tree in Development mode if page not found
-
-[#v0_6_0_documentation]
-=== Documentation
-
-* add documentation for Sender Policy Framework (RFC 7208)
-
-
-[#v0_5_0]
-== share v0.5.0 (2019-04-02)
-
-This minor release is dedicated for websocket package. Major refactoring on
-server and client API to make it easy and extensible. The websocket is now
-100% pass the autobahn testsuite (minus compression feature).
-
-[#v0_5_0_new_features]
-=== New features
-
-* `cmd/smtpcli`: command line interface to SMTP client protocol
-* `ints`: new package for working with slice of integer
-* `ints64`: new package for working with slice of 64 bit integer
-* `floats64`: new package for working with slice of 64 bit float
-
-[#v0_5_0_enhancements]
-=== Enhancements
-
-* `bytes`:
-** change the Copy return type to non pointer
-** add function to concat slice of byte or string into []byte
-
-* `ints`: add function to remove value from slice
-
-* `websockets`:
-** Rewrite most of client and server APIs to be more simple and pass autobahn
- testsuite
-** Minimize global variables and unexport internal constants and functions
-** Handle interjected PING control frame from server
-** Generate random mask only if masked field is set
-
-
-[#v0_4_0]
-== share v0.4.0 (2019-03-01)
-
-[#v0_4_0_new_features]
-=== New features
-
-* `email`: new package for working with Internet Message Format (RFC 5322)
-* `email/dkim`: new package for parsing and creating DKIM signature
- (RFC 6376)
-* `email/maildir`: new package to manage email using maildir format
-
-[#v0_4_0_enhancements]
-=== Enhancements
-
-* `bytes`
-** add function to copy slice
-** add function to convert hexadecimal into byte
-
-* `dns`
-** add mapping of connection types and its names
-** print the section question type by string
-** add method to filter Message.Answer by specific query type
-** add pool for UDP client
-** add function to get list of system name servers
-** make UDPClient Query routine safe
-** increase the internal debug level from 2 to 3
-
-* `http`
-** add the charset type to content-type "text/plain"
-** listen and serve using TLS if TLSConfig is defined
-** add method to temporary redirect request to other location
-
-* `ini`
-** unexport the reader
-** add method to get all variable values with the same key
-
-* `io`
-** rename Reader SkipSpace to SkipSpaces
-** refactoring, export all fields for easy access on Reader
-** add method read one line with line feed
-** add method to unread N characters on Reader
-** optimize ReadUntil without append
-** add method to return the rest of unreaded buffer on Reader
-** return the character separator that found on SkipUntil
-
-* `memfs`
-** add method to dump files as Go generated source
-** add variable for allowing bypass file in memory
-
-* `smtp` (work in progress)
-** rename StorageFile to LocalStorage
-** implement server with local handler
-** add prefix Mail to methods in Storage interface
-** use different port between normal listener and TLS listener
-
-* `time`: add function to get micro seconds
-
-[#v0_4_0_bug_fixes]
-=== Bug fixes
-
-* all: fix the usage of "iota"
-* `dns`: fix creating new UDP/TCP client without port number
-* `memfs`: check for empty directory on Mount
-
-
-[#v0_3_0]
-== share v0.3.0 (2019-02-01)
-
-[#v0_3_0_features_changes]
-=== Features Changes
-
-* `lib/debug`: add function to write heap profile to file
-* `lib/debug`: add type to store relative and difference on memory heap
-* `lib/dns`: remove request pool
-* `lib/dns`: export the connection field on UDPClient
-* `lib/dns`: add type of connection
-* `lib/http`: add parameter http.ResponseWriter to Callback.
-* `lib/http`: the RegisterXxx functions now use the Endpoint type.
-
-[#v0_3_0_enhancements]
-=== Enhancements
-
-* Various fixes suggested by linters
-* doc: add four summary and notes about DKIM
-* doc: add summary of Simple Authentication and Security Layer (SASL)
-* doc: add summary on SMTP over TLS (RFC3207)
-* doc: add notes for Internet Message Format (RFC 5322)
-* doc: add documentation for SMTP and DSN
-
-[#v0_3_0_bug_fixes]
-=== Bug fixes
-
-* `lib/git`: fix testdata and test input
-
-
-[#v0_2_0]
-== share v0.2.0 (2019-01-02)
-
-[#v0_2_0_new_features]
-=== New features
-
-* `lib/errors`, package errors provide a custom error with code.
-
-* `lib/http`, package http implement custom HTTP server with memory file
-system and simplified routing handler.
-
-[#v0_2_0_enhancements]
-=== Enhancements
-
-Fix warnings from linters.
-
-
-[#v0_1_0]
-== share v0.1.0 (2018-11-29)
-
-The first release of `share` package contains one command line interface (CLI)
-and several libraries.
-
-The CLI is `gofmtcomment` to convert comment from `+/**/+` to `//`.
-
-The libraries are `bytes`, `contact`, `dns`, `dsv`, `ini`, `io`, `memfs`,
-`mining`, `net`, `numbers`, `runes`, `strings`, `tabula`, `test`, `text`,
-`time`, and `websocket`.
-
-Documentation for each package can be viewed at,
-
- https://godoc.org/github.com/shuLhan/share
-
-I hope it will be stay alive!
diff --git a/_doc/CHANGELOG.html b/_doc/CHANGELOG.html
index bb15b863..99c9a887 100644
--- a/_doc/CHANGELOG.html
+++ b/_doc/CHANGELOG.html
@@ -296,278 +296,6 @@ dd {
<li><a href="#v0_33_0_chores">Chores</a></li>
</ul>
</li>
-<li><a href="#v0_32_0">share v0.32.0 (2021-12-03)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_32_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_32_0_new_features">New features</a></li>
-<li><a href="#v0_32_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_32_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_31_0">share v0.31.0 (2021-11-04)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_31_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_31_0_new_features">New features</a></li>
-<li><a href="#v0_31_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_31_0_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_30_0">share v0.30.0 (2021-10-04)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_30_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_30_0_new_features">New features</a></li>
-<li><a href="#v0_30_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_30_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_30_0_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_29_2">share v0.29.2 (2021-09-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_29_2_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_29_2_enhancements">Enhancements</a></li>
-<li><a href="#v0_29_2_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_29_1">share v0.29.1 (2021-08-06)</a></li>
-<li><a href="#v0_29_0">share v0.29.0 (2021-08-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_29_0_new_feature">New feature</a></li>
-<li><a href="#v0_29_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_29_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_29_0_bug_fixes">Bug fix</a></li>
-</ul>
-</li>
-<li><a href="#v0_28_0">share v0.28.0 (2021-07-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_28_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_28_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_27_0">share v0.27.0 (2021-06-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_27_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_27_0_new_features">New features</a></li>
-<li><a href="#v0_27_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_27_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_26_0">share v0.26.0 (2021-05-03)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_26_0_new_features">New features</a></li>
-<li><a href="#v0_26_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_26_0_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_25_1">share v0.25.1 (2021-04-06)</a></li>
-<li><a href="#v0_25_0">share v0.25.0 (2021-04-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_25_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_25_0_new_features">New features</a></li>
-<li><a href="#v0_25_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_24_0">share v0.24.0 (2021-03-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_24_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_24_0_new_features">New features</a></li>
-<li><a href="#v0_24_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_24_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_23_0">share v0.23.0 (2021-02-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_23_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_23_0_new_features">New features</a></li>
-<li><a href="#v0_23_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_23_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_22_0">share v0.22.0 (2021-01-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_22_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_22_0_new_features">New features</a></li>
-<li><a href="#v0_22_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_21_0">share v0.21.0 (2020-12-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_21_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_21_0_new_features">New features</a></li>
-<li><a href="#v0_21_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_21_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_21_0_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_20_1">share v0.20.1 (2020-11-08)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_20_1_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_20_1_enhancements">Enhancements</a></li>
-<li><a href="#v0_20_1_chores">Chores</a></li>
-</ul>
-</li>
-<li><a href="#v0_20_0">share v0.20.0 (2020-10-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_20_0_new_features">New features</a></li>
-<li><a href="#v0_20_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_19_0">share v0.19.0 (2020-09-08)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_19_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_19_0_new_features">New features</a></li>
-<li><a href="#v0_19_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_18_0">share v0.18.0 (2020-08-06)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_18_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_18_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_18_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_17_0">share v0.17.0 (2020-07-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_17_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_17_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_17_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_16_0">share v0.16.0 (2020-06-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_16_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_16_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_16_0_new_features">New features</a></li>
-<li><a href="#v0_16_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_15_0">share v0.15.0 (2020-05-04)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_15_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_15_0_new_features">New features</a></li>
-<li><a href="#v0_15_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_15_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_14_0">share v0.14.0 (2020-04-03)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_14_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_14_0_new_features">New features</a></li>
-<li><a href="#v0_14_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_14_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_13_0">share v0.13.0 (2020-03-11)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_13_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_13_0_new_features">New features</a></li>
-<li><a href="#v0_13_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_13_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_12_0">share v0.12.0 (2020-02-13)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_12_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_12_0_new_features">New features</a></li>
-<li><a href="#v0_12_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_12_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_11_0">share v0.11.0 (2019-12-26)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_11_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_11_0_new_features">New features</a></li>
-<li><a href="#v0_11_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_11_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_10_2">share v0.10.2 (2019-12-07)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_10_2_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_10_1">share v0.10.1 (2019-12-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_10_1_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_10_1_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_10_0">share v0.10.0 (2019-11-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_10_0_new_features">New features</a></li>
-<li><a href="#v0_10_0_breaking_changes">Breaking Changes</a></li>
-<li><a href="#v0_10_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_10_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_9_0">share v0.9.0 (2019-10-08)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_9_0_new_features">New features</a></li>
-<li><a href="#v0_9_0_breaking_changes">Breaking Changes</a></li>
-<li><a href="#v0_9_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_9_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_8_2">share v0.8.2 (2019-09-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_8_2_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_8_1">share v0.8.1 (2019-08-05)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_8_1_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_8_0">share v0.8.0 (2019-07-09)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_8_0_breaking_changes">Breaking changes</a></li>
-<li><a href="#v0_8_0_new_features">New features</a></li>
-<li><a href="#v0_8_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_7_0">share v0.7.0 (2019-06-14)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_7_0_breaking_changes">Breaking Changes</a></li>
-<li><a href="#v0_7_0_new_features">New features</a></li>
-<li><a href="#v0_7_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_7_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_6_1">share v0.6.1 (2019-05-11)</a></li>
-<li><a href="#v0_6_0">share v0.6.0 (2019-05-07)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_6_0_breaking_changes">Breaking Changes</a></li>
-<li><a href="#v0_6_0_new_features">New features</a></li>
-<li><a href="#v0_6_0_bug_fixes">Bug fixes</a></li>
-<li><a href="#v0_6_0_documentation">Documentation</a></li>
-</ul>
-</li>
-<li><a href="#v0_5_0">share v0.5.0 (2019-04-02)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_5_0_new_features">New features</a></li>
-<li><a href="#v0_5_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_4_0">share v0.4.0 (2019-03-01)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_4_0_new_features">New features</a></li>
-<li><a href="#v0_4_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_4_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_3_0">share v0.3.0 (2019-02-01)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_3_0_features_changes">Features Changes</a></li>
-<li><a href="#v0_3_0_enhancements">Enhancements</a></li>
-<li><a href="#v0_3_0_bug_fixes">Bug fixes</a></li>
-</ul>
-</li>
-<li><a href="#v0_2_0">share v0.2.0 (2019-01-02)</a>
-<ul class="sectlevel2">
-<li><a href="#v0_2_0_new_features">New features</a></li>
-<li><a href="#v0_2_0_enhancements">Enhancements</a></li>
-</ul>
-</li>
-<li><a href="#v0_1_0">share v0.1.0 (2018-11-29)</a></li>
</ul>
</div>
@@ -578,6 +306,18 @@ dd {
<div class="paragraph">
<p>This library is released every month, usually at the first week of month.</p>
</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2021.html" target="_blank" rel="noopener">Changelog in 2021</a>.
+This is changelog for share module since v0.22.0 until v0.32.0.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2020.html" target="_blank" rel="noopener">Changelog in 2020</a>.
+This is changelog for share module since v0.12.0 until v0.21.0.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2018-2019.html" target="_blank" rel="noopener">Changelog from 2018 to 2019</a>.
+This is changelog for share module since v0.1.0 until v0.11.0.</p>
+</div>
</div>
</div>
<div class="sect1">
@@ -1851,4591 +1591,10 @@ at the same times.</p>
</div>
</div>
</div>
-<div class="sect1">
-<h2 id="v0_32_0"><a class="anchor" href="#v0_32_0"></a><a class="link" href="#v0_32_0">share v0.32.0 (2021-12-03)</a></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="v0_32_0_breaking_changes"><a class="anchor" href="#v0_32_0_breaking_changes"></a><a class="link" href="#v0_32_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>math/big: refactoring AddFloat to accept variadic interface{}</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the AddFloat function only accept two interface parameters.</p>
-</div>
-<div class="paragraph">
-<p>This changes make the AddFloat to accept many interface parameters.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>math/big: refactor NewFloat to accept interface{} instead of float64 only</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>math/big: refactoring the Rat</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The promise of this package is to provide the Rat type with RoundToZero
-and without panic.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>Another breaking changes are,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</ul>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring, change signature of client Lookup</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, Lookup() method on Client pass the question name, type, and
-class as parameters.</p>
-</div>
-<div class="paragraph">
-<p>This changes make those parameters into MessageQuestion.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring ZoneFile into Zone</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Reason: A Zone is not always represented by file, it just that in this
-package, it is.</p>
-</div>
-<div class="paragraph">
-<p>This changes rename the type ZoneFile into Zone.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring message question</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously the type for message question section SectionQuestion.</p>
-</div>
-<div class="paragraph">
-<p>This changes, rename the type to MessageQuestion.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring the section header</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>This changes rename the SectionHeader into MessageHeader.</p>
-</div>
-<div class="paragraph">
-<p>The pack() method is optimized with the following results,</p>
-</div>
-<div class="paragraph">
-<p>benchmark old ns/op new ns/op delta
-BenchmarkMessageHeader_pack-8 66.2 21.7 -67.31%</p>
-</div>
-<div class="paragraph">
-<p>benchmark old allocs new allocs delta
-BenchmarkMessageHeader_pack-8 3 1 -66.67%</p>
-</div>
-<div class="paragraph">
-<p>benchmark old bytes new bytes delta
-BenchmarkMessageHeader_pack-8 32 16 -50.00%</p>
-</div>
-<div class="paragraph">
-<p>The unpack() method is simplified by minimizing the if-condition.</p>
-</div>
-<div class="paragraph">
-<p>This changes also fix the pack and unpack OpCode for value other then 0,
-due to wrong shift value, 2 instead of 3.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring, introduce new type RecordClass</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the record class is represented by uint16 using prefix
-QueryClassXxx.</p>
-</div>
-<div class="paragraph">
-<p>This changes make the record class to be an independent type, to make
-code more strict (prevent passing invalid value), and readable.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: refactoring, create type RecordType to represent type of RR</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, we use uint16 to represent type for ResourceRecord Type or
-Question type.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: remove the fallback name servers (NS) from server options</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This changes remove the unnecessary and complex fallback NS from
-server.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_32_0_new_features"><a class="anchor" href="#v0_32_0_new_features"></a><a class="link" href="#v0_32_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/dns: add support to save and load caches to/from storage</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The CachesSave method write the non-local answers into an io.Writer,
-encoded with gob.</p>
-</div>
-<div class="paragraph">
-<p>The CachesLoad method load the gob encoded answers from an io.Reader.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/ssh: use agent defined by config or from environment variable</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>ssh/config: add support for section variable IdentityAgent</p>
-<div class="paragraph">
-<p>There are four possible value for IdentityAgent: SSH_AUTH_SOCK,
-&lt;$STRING&gt;, &lt;PATH&gt;, 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.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_32_0_bug_fixes"><a class="anchor" href="#v0_32_0_bug_fixes"></a><a class="link" href="#v0_32_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>math/big: return nil on Quo and QuoRat instead of panic</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This changes make it less intrusive, instead of panic we check for
-zero value and return nil immediately.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: do not cache truncated answer</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously only answer with non-zero response code is ignored.</p>
-</div>
-<div class="paragraph">
-<p>This changes ignore also answer where response header is truncated.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_32_0_enhancements"><a class="anchor" href="#v0_32_0_enhancements"></a><a class="link" href="#v0_32_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/dns: realign all struct fields</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Turns out the struct that we frequently used, answer and resource_record,
-is not optimized.</p>
-</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="paragraph">
-<p>This changes reorder all structs field to save space in memory.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: make the TCP forwarders as complementary of UDP</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/dns: use different packet between UDP and TCP messages</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, all packet size for reading and sending the message is
-fixed to 4096, even on UDP.</p>
-</div>
-<div class="paragraph">
-<p>This changes set the UDP packet size maximum to 512 bytes and others to
-4096 bytes.</p>
-</div>
-<div class="paragraph">
-<p>While at it, minimize copying packet if its not reusable inside a method.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_31_0"><a class="anchor" href="#v0_31_0"></a><a class="link" href="#v0_31_0">share v0.31.0 (2021-11-04)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_31_0_breaking_changes"><a class="anchor" href="#v0_31_0_breaking_changes"></a><a class="link" href="#v0_31_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/memfs: move the embedded parameter to Options</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This commit add new type EmbedOptions that contains the parameters
-for GoEmbed.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/totp: make the New to accept only hash with SHA1, SHA256, or SHA512</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This changes update the New function signature to accept defined
-type that can be set to SHA1, SHA256, or SHA512.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/bytes: refactoring and cleaning up the bytes package</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>A breaking changes,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</li>
-</ul>
-</div>
-<div class="paragraph">
-<p>Bug fixes,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</li>
-</ul>
-</div>
-<div class="paragraph">
-<p>We move all unit test to example so we have test and example in the
-documentation at the same time.</p>
-</div>
-<div class="paragraph">
-<p>This changes make all test coverage 100%.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/bytes: refactoring AppendXxx functions</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>lib/ascii: change signature of ToLower and ToUpper</p>
-<div class="paragraph">
-<p>Using pointer to slice on method or function is not a Go idiom.
-It is created when I still new to Go.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: refactoring Node field V into Content</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The reason why the field named V is because it&#8217;s short. It&#8217;s come
-from my C/C++ experience that got carried away when writing this
-package.</p>
-</div>
-<div class="paragraph">
-<p>Now, after having more time writing Go, I prefer clarity over
-cleverity(?).</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: set the node modification time in embedded file</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>This changes set all node modification time in embedded files to
-the node modTime using Unix() and Nanosecond() values.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_31_0_new_features"><a class="anchor" href="#v0_31_0_new_features"></a><a class="link" href="#v0_31_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/ini: add function IsValidVarName</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: set the node modification time in embedded file</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>This changes set all node modification time in embedded files to
-the node modTime using Unix() and Nanosecond() values.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/io: add method String to FileState type</p>
-<div class="paragraph">
-<p>The String method return the string representation of FileState.
-Usually used only for debugging.</p>
-</div>
-</li>
-<li>
-<p>lib/smtp: implement method Noop on Client</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Noop send the NOOP command to server with optional message.</p>
-</div>
-<div class="paragraph">
-<p>On success, it will return response with Code 250, StatusOK.</p>
-</div>
-<div class="paragraph">
-<p>While at it fix double call to recv on Reset() method.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/smtp: implement method Reset on Client</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The Reset() method send the STMP RSET command to the server.</p>
-</div>
-<div class="paragraph">
-<p>This command clear the current buffer on MAIL, RCPT, and DATA, but not the
-EHLO/HELO buffer.</p>
-</div>
-<div class="paragraph">
-<p>On success, it will return response with Code 250, StatusOK.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_31_0_bug_fixes"><a class="anchor" href="#v0_31_0_bug_fixes"></a><a class="link" href="#v0_31_0_bug_fixes">Bug fixes</a></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="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Use case:</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>x
-x/y</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>If x/y is empty, and x processed first, the x will
-not be removed.</p>
-</div>
-<div class="paragraph">
-<p>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,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>x/y
-x</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>While at it, update an example of New to give preview of input and
-what the expected output for certain operations.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/xmlrpc: rewrite the Client connection using lib/http</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Using socket connection require reading the HTTP response header before
-we can process the response body.</p>
-</div>
-<div class="paragraph">
-<p>Instead of rewrite the parser, use the lib/http to send and receive
-the request/response.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/io: do not use absolute path on dummy Watcher parent SysPath</p>
-<div class="paragraph">
-<p>Converting that parameter path to absolute path may cause unpredictable
-result on module that use it.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_31_0_chores"><a class="anchor" href="#v0_31_0_chores"></a><a class="link" href="#v0_31_0_chores">Chores</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/ini: add example of marshal/unmarshaling of section with sub</p>
-<div class="paragraph">
-<p>This changes also fix the example of field tag on marshaling the
-map.</p>
-</div>
-</li>
-<li>
-<p>lib/io: add method String to FileState type</p>
-<div class="paragraph">
-<p>The String method return the string representation of FileState.
-Usually used only for debugging.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: remove unnecessary initialization on NewNode</p>
-<div class="paragraph">
-<p>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.</p>
-</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="v0_30_0"><a class="anchor" href="#v0_30_0"></a><a class="link" href="#v0_30_0">share v0.30.0 (2021-10-04)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_30_0_breaking_changes"><a class="anchor" href="#v0_30_0_breaking_changes"></a><a class="link" href="#v0_30_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/io: separate FileState for updated mode and content</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This changes separated those state into two kind: FileStateUpdateMode
-for update on file mode, and FileStateUpdateContent for update on
-file content.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_30_0_new_features"><a class="anchor" href="#v0_30_0_new_features"></a><a class="link" href="#v0_30_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/memfs: export the Node Update method</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>The newInfo parameter is optional, if its nil, it will read the file
-information based on node&#8217;s SysPath.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/strings: add function Alnum</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_30_0_bug_fixes"><a class="anchor" href="#v0_30_0_bug_fixes"></a><a class="link" href="#v0_30_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/memfs: fix symlink to directory not included on mount</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>The fix is to check if node mode is symlink first and then get the
-the real stat.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/io: fix NewWatcher when called DirWatcher</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>When NewWatcher called from DirWatcher&#8217;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.</p>
-</div>
-<div class="paragraph">
-<p>Any operation using new node SysPath will failed because the path
-does not exist or reachable from current directory.</p>
-</div>
-<div class="paragraph">
-<p>For example, let say we have the following directory tree,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>testdata
-|
-+--- A
-|
-+--- B</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>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", &#8230;&#8203;). 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".</p>
-</div>
-<div class="paragraph">
-<p>Later, when node content need to be read, ioutil.ReadFile("A") will
-fail because the path to "A" does not exist on current directory.</p>
-</div>
-<div class="paragraph">
-<p>This fix require to force the parameter "parent" on NewNode to be
-required.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: fix possible data race on PathNode</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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()</p>
-</div>
-<div class="paragraph">
-<p>At the same time, there maybe a request to access another path, which
-cause both read and write occured.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: fix NewNode if node is symlink to directory</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, if a symlink point to directory the memfs NewNode function
-will return an error,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>AddChild wui: NewNode: read x/y: is a directory</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>which cause the files inside y cannot be scanned (404).</p>
-</div>
-<div class="paragraph">
-<p>This commit fix this issue by checking if the original node mode is a
-directory and return immediately.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_30_0_enhancements"><a class="anchor" href="#v0_30_0_enhancements"></a><a class="link" href="#v0_30_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/memfs: check error on File Close on GoGenerate</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, we ignore the error for call to Close when there is an
-error in previous operation.</p>
-</div>
-<div class="paragraph">
-<p>This changes check the error returned from Close and add it to the
-returned error message.</p>
-</div>
-<div class="paragraph">
-<p>While at it, use consisten prefix for all returned error:
-"MemFS.GoGenerate".</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/http: support server caching file system using ETag</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>If the Server handle file system using MemFS, server will set the
-ETag [1] header using the file epoch as value.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>[1] <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag" class="bare">https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag</a></p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/xmlrpc: convert the value using Sprintf on GetFieldAsString</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the GetFieldAsString will return empty string if the
-Value type is not string.</p>
-</div>
-<div class="paragraph">
-<p>In this commit, we force the value to be string by converted it using
-fmt.Sprintf.</p>
-</div>
-</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="v0_30_0_chores"><a class="anchor" href="#v0_30_0_chores"></a><a class="link" href="#v0_30_0_chores">Chores</a></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="v0_29_2"><a class="anchor" href="#v0_29_2"></a><a class="link" href="#v0_29_2">share v0.29.2 (2021-09-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_29_2_bug_fixes"><a class="anchor" href="#v0_29_2_bug_fixes"></a><a class="link" href="#v0_29_2_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>os/exec: fix escaped quote inside the same quote</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Shell quote is a hell of complex. For example, one can write
-shell that execute command that contains quote of quote,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>sh -c "psql -c 'CREATE ... IDENTIFIED BY PASSWORD '\''pass'\'''"</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>or to simplify,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>sh -c "psql -c \"CREATE ... IDENTIFIED BY PASSWORD 'pass'\""</pre>
-</div>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: fix empty ContentType if MaxFileSize is negative</p>
-<div class="paragraph">
-<p>A negative MaxFileSize means the content of file will not be mapped to
-memory, but the content type should be detected for other operation.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: fix empty file not being added to tree</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This commit fix this issue by checking for zero file size and for
-io.EOF when reading the file content.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: fix symbolic link with different name</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>parentpath/filename: no such file or directory</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>because we use the original file name, not the symlinked file name.</p>
-</div>
-<div class="paragraph">
-<p>This commit fix this issue by not replacing the original FileInfo for
-symlink but by setting only the size and mode.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/sql: do not run migration if the last file not exist on the list</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, if the last migrated file name not found on the migration
-directory, we start executing migration start from the first file.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/http: fix missing content type for XML Header</p>
-<div class="paragraph">
-<p>If the Endpoint set the RequestType to RequestTypeXML, the response
-header should be set to ContentTypeXML.</p>
-</div>
-</li>
-<li>
-<p>lib/xmlrpc: fix missing port on NewClient</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Calling net.Dial or tls.Dial on host without port will cause the
-following error,</p>
-</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="paragraph">
-<p>This changes fix this by always generate new host value using previous
-host and port values.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/smtp: return io.EOF if no data received from server</p>
-<div class="paragraph">
-<p>This is to prevent the recv return nil on *Response without an error,
-which may cause panic on caller side.</p>
-</div>
-</li>
-<li>
-<p>os/exec: check for escaped backslash when ParseCommandArgs</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_29_2_enhancements"><a class="anchor" href="#v0_29_2_enhancements"></a><a class="link" href="#v0_29_2_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/memfs: set default content type for empty file to "text/plain"</p>
-<div class="paragraph">
-<p>An empty file should be able to be displayed as text file instead of
-downloaded as binary.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: change the MarshalJSON to always return an object</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, MarshalJSON on memfs will return an object of map
-of all PathNodes and on Node it will return an object.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>While at it, use single "mod_time" with value is epoch and return
-the node ContentType as "content_type".</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/mlog: implement io.Writer and add function ErrorWriter</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The ErrorWriter will return the internal default MultiLogger.
-A call to Write() on returned io.Writer will forward it to all registered
-error writers.</p>
-</div>
-<div class="paragraph">
-<p>A Write method on MultiLogger write the b to all error writers.
-It will always return the length of b without an error.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/memfs: add method Save and Encode</p>
-<div class="paragraph">
-<p>The Save method will write the new content to file system and update
-the content of Node using Encode().</p>
-</div>
-</li>
-<li>
-<p>lib/ssh: add method to set session output and error</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, all of the SSH output and error goes to os.Stdout and
-os.Stderr.</p>
-</div>
-<div class="paragraph">
-<p>This changes add method SetSessionOutputError to change the output and
-error for future remote execution.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_29_2_chores"><a class="anchor" href="#v0_29_2_chores"></a><a class="link" href="#v0_29_2_chores">Chores</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/reflect: make the IsNil tests to become an example</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>In this way we do test and provide an example at the same time.</p>
-</div>
-<div class="paragraph">
-<p>While at it, add another test cases for boolean, initialized slice, map,
-and errors.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/websocket: try to fix flaky test on client</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The following error thrown when running on Github Action using
-Ubuntu-latest and Go 1.16.3,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>client_test.go:472: write tcp 127.0.0.1:34460-&gt;127.0.0.1:9001:
-write: connection reset by peer</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>This may be caused by using the same client connection on all test
-cases.</p>
-</div>
-<div class="paragraph">
-<p>We try to fix this by creating new client on each test cases.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_29_1"><a class="anchor" href="#v0_29_1"></a><a class="link" href="#v0_29_1">share v0.29.1 (2021-08-06)</a></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="v0_29_0"><a class="anchor" href="#v0_29_0"></a><a class="link" href="#v0_29_0">share v0.29.0 (2021-08-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_29_0_new_feature"><a class="anchor" href="#v0_29_0_new_feature"></a><a class="link" href="#v0_29_0_new_feature">New feature</a></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="v0_29_0_breaking_changes"><a class="anchor" href="#v0_29_0_breaking_changes"></a><a class="link" href="#v0_29_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>text/diff: add functions to compare raw bytes as text and text.Lines</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>This changes refactoring some functions, notably,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_29_0_enhancements"><a class="anchor" href="#v0_29_0_enhancements"></a><a class="link" href="#v0_29_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/mlog: add function and method Panicf</p>
-<div class="paragraph">
-<p>The Panicf method is equal to Errf followed by panic. This signature
-follow the log.Panicf convention.</p>
-</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="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, without MarshalJSON, encoding the MemFS or Node object will
-result in incomplete information, for example, missing name, modification
-time, and size.</p>
-</div>
-<div class="paragraph">
-<p>This commit implement the json.Marshaler in MemFS which encode the
-PathNode sorted by keys in ascending order.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/bytes: print the ASCII character on the right side on PrintHex</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, PrintHex only print the hex value of all bytes with
-specified length.</p>
-</div>
-<div class="paragraph">
-<p>This changes also print any printables ASCII characters (char 33 through
-126) in the right side column to view readable contents.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>lib/totp: lib/totp: increase the maximum steps back on Verify from 2 to 20</p>
-<div class="paragraph">
-<p>The value 20 means the Verify will check maximum 20 TOTP tokens or 10
-minutes to the past.</p>
-</div>
-</li>
-<li>
-<p>lib/http: check request path as HTML file on getFSNode</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, if the request path is not exist we check if request
-contains index.html and if still not exist we return nil.</p>
-</div>
-<div class="paragraph">
-<p>This commit add another check by appending ".html" to the request path.</p>
-</div>
-<div class="paragraph">
-<p>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".</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_29_0_bug_fixes"><a class="anchor" href="#v0_29_0_bug_fixes"></a><a class="link" href="#v0_29_0_bug_fixes">Bug fix</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/errors: return the internal error only if its not nil on Unwrap</p>
-<div class="paragraph">
-<p>If the internal error is nil, the Unwrap method will return the instance
-of e itself.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_28_0"><a class="anchor" href="#v0_28_0"></a><a class="link" href="#v0_28_0">share v0.28.0 (2021-07-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_28_0_breaking_changes"><a class="anchor" href="#v0_28_0_breaking_changes"></a><a class="link" href="#v0_28_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/ssh: rename method Get to ScpGet and Put to ScpPut</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>While at it, use consistent log prefix for error message.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>ssh: rename the NewClient function to NewClientFromConfig</p>
-<div class="paragraph">
-<p>This is to differentiate it with x/crypto ssh package that have the same
-function name.</p>
-</div>
-</li>
-<li>
-<p>ssh: move the config parser to subpackage "config"</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>http: remove the Memfs field from Server</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_28_0_enhancements"><a class="anchor" href="#v0_28_0_enhancements"></a><a class="link" href="#v0_28_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>websocket: export the Options field on the Server</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the Options field is not exported to prevent user from
-changing it once it set through NewServer() function.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>http: export the Options field on the Server</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the Options field is not exported to prevent user from
-changing it once it set through NewServer() function.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>websocket: store all the handshake headers to Handshake.Header</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously only non-required headers are stored in the Handshake Header
-field, while the required header value stored on their respective fields.</p>
-</div>
-<div class="paragraph">
-<p>This commit store all request header key and values into the Header field.</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_27_0"><a class="anchor" href="#v0_27_0"></a><a class="link" href="#v0_27_0">share v0.27.0 (2021-06-05)</a></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="v0_27_0_breaking_changes"><a class="anchor" href="#v0_27_0_breaking_changes"></a><a class="link" href="#v0_27_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>xmlrpc: change the Response to embed the errors.E</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>xmlrpc: write the XML header when marshaling request not on client</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the XML header is added when sending the request using
-client.</p>
-</div>
-<div class="paragraph">
-<p>This commit changes it to write the header when marshaling the Request
-instance.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>xmlrpc: replace Value field for struct with map of string and value</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, for param with type "struct" is represented by slice of
-Member{Name,Value}.</p>
-</div>
-<div class="paragraph">
-<p>This commit changes the Value field for "struct" to a map of string and
-value for easily access the struct&#8217;s member, without looping.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>xmlrpc: refactoring the parser for decoding XML-RPC request</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>This changes,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_27_0_new_features"><a class="anchor" href="#v0_27_0_new_features"></a><a class="link" href="#v0_27_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>memfs: add function to Merge one or more instance of MemFS</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The Merge function merge one or more instance of MemFS into single MemFS
-instance.</p>
-</div>
-<div class="paragraph">
-<p>If there are two instance of Node that have the same path, the last
-instance will be ignored.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>xmlrpc: add method to marshal Response</p>
-</li>
-<li>
-<p>mlog: add function and method PrintStack</p>
-<div class="paragraph">
-<p>The PrintStack function or method will writes to error writers the stack
-trace returned by debug.Stack.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_27_0_enhancements"><a class="anchor" href="#v0_27_0_enhancements"></a><a class="link" href="#v0_27_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: add request type for XML</p>
-<div class="paragraph">
-<p>Setting Endpoint&#8217;s RequestType to RequestTypeXML will check the content
-type of HTTP request to match with "text/xml".</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_27_0_bug_fixes"><a class="anchor" href="#v0_27_0_bug_fixes"></a><a class="link" href="#v0_27_0_bug_fixes">Bug fixes</a></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="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>xmlrpc: set client response IsFault when StatusCode &gt;= 400</p>
-<div class="paragraph">
-<p>Previously, we set IsFault to true if the HTTP response code not equal to
-200 only, which is not always correct.</p>
-</div>
-<div class="paragraph">
-<p>This commit changes it to check any status code that is greater or equal
-to 400.</p>
-</div>
-</li>
-<li>
-<p>memfs: fix test by checking multiple content-types</p>
-<div class="paragraph">
-<p>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".</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_26_0"><a class="anchor" href="#v0_26_0"></a><a class="link" href="#v0_26_0">share v0.26.0 (2021-05-03)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_26_0_new_features"><a class="anchor" href="#v0_26_0_new_features"></a><a class="link" href="#v0_26_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>math/big: add method Add, IsLess, IsGreater, and Scan on Int</p>
-<div class="paragraph">
-<p>The Add method simplify addition of one value to current Int.</p>
-</div>
-<div class="paragraph">
-<p>The IsLess and IsGreater method simplify comparing Int with any value.</p>
-</div>
-<div class="paragraph">
-<p>The Scan method allow the Int to be used on sql Scan().</p>
-</div>
-</li>
-<li>
-<p>math/big: add method IsZero on Int</p>
-<div class="paragraph">
-<p>The IsZero method will return true if the current i value is zero.</p>
-</div>
-</li>
-<li>
-<p>big: extends the standard big.Int</p>
-<div class="paragraph">
-<p>The standard big.Int does not implement sql/driver.Valuer interface,
-which make it not usable when querying or doing update/insert with
-database.</p>
-</div>
-<div class="paragraph">
-<p>This commit extend the big.Int and simplify creating new Int from any
-values using NewInt().</p>
-</div>
-<div class="paragraph">
-<p>Also, make it support marshal/unmarshal JSON</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_26_0_enhancements"><a class="anchor" href="#v0_26_0_enhancements"></a><a class="link" href="#v0_26_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>sql: make the column filename on table _migration as primary key</p>
-<div class="paragraph">
-<p>This will allow deleting the record by filename instead of requiring
-all columns.</p>
-</div>
-</li>
-<li>
-<p>http: add the Total field to EndpointResponse</p>
-<div class="paragraph">
-<p>The Total field contains the total number of all records, while the
-Count fields only contains the total number of records in Data.</p>
-</div>
-</li>
-<li>
-<p>http: add field Page to EndpointResponse</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>While at it, move the field comment to its declaration.</p>
-</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="paragraph">
-<p>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.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_26_0_chores"><a class="anchor" href="#v0_26_0_chores"></a><a class="link" href="#v0_26_0_chores">Chores</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>memfs: update the test ContentType for JavaScript files</p>
-<div class="paragraph">
-<p>The latest Go set the content type for JavaScript file as
-"text/javascript; charset=utf-8", not "application/javascript".</p>
-</div>
-</li>
-<li>
-<p>paseto: replace le64() function with binary.Write()</p>
-<div class="paragraph">
-<p>The le64() return the string representation of uint64 in little endian,
-which is basically binary.Write with parameter output buffer,
-LittleEndian, and input value.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_25_1"><a class="anchor" href="#v0_25_1"></a><a class="link" href="#v0_25_1">share v0.25.1 (2021-04-06)</a></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="v0_25_0"><a class="anchor" href="#v0_25_0"></a><a class="link" href="#v0_25_0">share v0.25.0 (2021-04-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_25_0_breaking_changes"><a class="anchor" href="#v0_25_0_breaking_changes"></a><a class="link" href="#v0_25_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>all: refactoring the test.Assert and test.AssertBench signature</p>
-<div class="paragraph">
-<p>Previously, the test.Assert and test.AssertBench functions has the
-boolean parameter to print the stack trace of test in case its not equal.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>all: refactoring http.Client methods signature</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, parameters to method Delete, Get, Post, PostForm, PostFormData,
-PostJSON, Put, and PutJSON are in the following order:</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>(headers, path, params)</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>This is sometimes confusing. To make it better and works with format
-of HTTP request header,</p>
-</div>
-<div class="listingblock">
-<div class="content">
-<pre>METHOD PATH
-HEADERS
-
-PARAMS</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>we move the path to the first parameter and headers as the second
-parameter, so the call to client methods would be</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>(path, headers, params)</pre>
-</div>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>http: remove parameter contentType on Client method Put</p>
-<div class="paragraph">
-<p>Since one can set the Content-Type in parameter headers, this parameter is
-become redundant.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_25_0_new_features"><a class="anchor" href="#v0_25_0_new_features"></a><a class="link" href="#v0_25_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: add method to generate standard HTTP request on Client</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>The GenerateHttpRequest method generate http.Request instance from
-method, path, requestType, headers, and params.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>For HTTP method is PATCH, POST, or PUT; the params will converted based on
-requestType rules below,</p>
-</div>
-<div class="ulist">
-<ul>
-<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>
-</ul>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>ssh: ask for passphrase if private key is encrypted on generateSigners</p>
-<div class="paragraph">
-<p>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().</p>
-</div>
-<div class="paragraph">
-<p>This changes also remove call to generateSigners on postConfig(),
-instead invoke it from NewClient() to minimize multiple calls to
-generateSigners().</p>
-</div>
-</li>
-<li>
-<p>ssh: use the SSH agent to authenticate on NewClient</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This method need manual key added by user to SSH agent before calling
-NewClient to make it works.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_25_0_enhancements"><a class="anchor" href="#v0_25_0_enhancements"></a><a class="link" href="#v0_25_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>xmlrpc: add debug statements to print request and response</p>
-<div class="paragraph">
-<p>The debug level is set minimum to 3. If its set it will print the
-request and response to standard output.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_24_0"><a class="anchor" href="#v0_24_0"></a><a class="link" href="#v0_24_0">share v0.24.0 (2021-03-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_24_0_breaking_changes"><a class="anchor" href="#v0_24_0_breaking_changes"></a><a class="link" href="#v0_24_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: add prefix Header to constants AcceptEncoding and ContentEncoding</p>
-<div class="paragraph">
-<p>Since both of those constants are used only for HTTP header, it could
-be more clear if we prefix it with "Header".</p>
-</div>
-</li>
-<li>
-<p>sql: change the parameter ExtractSQLFields to driver name</p>
-<div class="paragraph">
-<p>Previously, we use the string as parameter to set the returned place
-holders.</p>
-</div>
-<div class="paragraph">
-<p>This commit changes the parameter to the driver name so if the value
-is "postgres" the place holders will be returned as counter, for example
-"$1", "$2", and so on.</p>
-</div>
-</li>
-<li>
-<p>http: rename "GenericResponse" to "EndpointResponse"</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-<li>
-<p>http: refactoring parameters on Callback and CallbackErrorHandler</p>
-<div class="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>This changes wrap the three parameters into single type EndpointRequest
-with addition field Endpoint, which contains the registered Endpoint.</p>
-</div>
-<div class="paragraph">
-<p>On the CallbackErrorHandler we also have three parameters, but instead
-of request body we have an error.</p>
-</div>
-<div class="paragraph">
-<p>This changes store the error for CallbackErrorHandler inside
-EndpointRequest.Error field.</p>
-</div>
-</li>
-<li>
-<p>http: move the CORS options to separate struct</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_24_0_new_features"><a class="anchor" href="#v0_24_0_new_features"></a><a class="link" href="#v0_24_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: add methods IPAddressOfRequest and ParseXForwardedFor</p>
-<div class="paragraph">
-<p>The IPAddressOfRequest get the client IP address from HTTP request header
-"X-Real-IP" or "X-Forwarded-For" or from Request.RemoteAddr, which ever
-non-empty first.</p>
-</div>
-<div class="paragraph">
-<p>The ParseXForwardedFor parse the HTTP header "X-Forwarded-For" value from
-the following format "client, proxy1, proxy2" into client address and
-list of proxy addressess.</p>
-</div>
-</li>
-<li>
-<p>api/slack: create new client for webhook</p>
-<div class="paragraph">
-<p>Unlike PostWebhook API which is close and open one connection at the
-time, the WebhookClient is keep open.</p>
-</div>
-<div class="paragraph">
-<p>Use the WebhookClient for long running program that post message every
-minutes or seconds.</p>
-</div>
-</li>
-<li>
-<p>mlog: implement MultiLogger</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>MultiLogger represent a single log writer that write to multiple outputs.
-MultiLogger can have zero or more writers for standard output (normal log)
-and zero or more writers for standard error.</p>
-</div>
-<div class="paragraph">
-<p>The MultiLogger is buffered to minimize waiting time when writing to
-multiple writers that have different latencies.
-For example, if we have one writer to os.Stdout, one writer to file, and
-one writer to network; the writer to network may take more time to finish
-than to os.Stdout and file, which may slowing down the program if we want
-to wait for all writes to finish.</p>
-</div>
-<div class="paragraph">
-<p>For this reason, do not forget to call Flush when your program exit.</p>
-</div>
-<div class="paragraph">
-<p>The default MultiLogger use time.RFC3339 as the default time layout, empty
-prefix, os.Stdout for the output writer, and os.Stderr for the error
-writer.</p>
-</div>
-<div class="paragraph">
-<p>Format of written log,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>[time] [prefix] &lt;message&gt;</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>The time and prefix only printed if its not empty, and the single space is
-added for convenience.
-Unlike standard log package, this package does not add new line to the end
-of message if its not exist.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>http: export the HandleFS method</p>
-<div class="paragraph">
-<p>The HandleFS handle the request as resource in the memory file system.
-This method only works if the Server.Memfs is not nil.</p>
-</div>
-<div class="paragraph">
-<p>If the request Path exists in file system, it will return 200 OK with the
-header Content-Type set accordingly to the detected file type and the
-response body set to the content of file.
-If the request Method is HEAD, only the header will be sent back to client.</p>
-</div>
-<div class="paragraph">
-<p>If the request Path is not exist it will return 404 Not Found.</p>
-</div>
-</li>
-<li>
-<p>clise: add method Pop</p>
-<div class="paragraph">
-<p>The Pop method remove the last Push()-ed item and return it to caller.
-It will return nil if no more item inside it.</p>
-</div>
-</li>
-<li>
-<p>ini: add support for marshaling slice of struct</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Given a struct with exported field is slice of struct and tagged with
-section and sub-section, the exported field will be marshalled as,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>[section "sub"]
-field = value</pre>
-</div>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>ini: add support for marshaling pointer to struct and to time.Time</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Given the following field struct with tag,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>V *T `ini:"sec:sub"</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>If the V is not nil, it will marshal it into,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>[sec "sub"]
-&lt;field name or tag&gt; = &lt;field value&gt;</pre>
-</div>
-</div>
-</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="paragraph">
-<p>The Rat.Value() return the value as []byte.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_24_0_enhancements"><a class="anchor" href="#v0_24_0_enhancements"></a><a class="link" href="#v0_24_0_enhancements">Enhancements</a></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="paragraph">
-<p>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.</p>
-</div>
-<div class="paragraph">
-<p>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.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_24_0_bug_fixes"><a class="anchor" href="#v0_24_0_bug_fixes"></a><a class="link" href="#v0_24_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>reflect: check using equal statement on IsNil</p>
-<div class="paragraph">
-<p>Beside using IsNil(), return the last check using "v == nil".</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_23_0"><a class="anchor" href="#v0_23_0"></a><a class="link" href="#v0_23_0">share v0.23.0 (2021-02-05)</a></h2>
-<div class="sectionbody">
-<div class="paragraph">
-<p>This release bring major refactoring to package memfs to allow embedding two
-or more directories in single package.</p>
-</div>
-<div class="paragraph">
-<p>The minimum Go version is increased to 1.14.</p>
-</div>
-<div class="sect2">
-<h3 id="v0_23_0_breaking_changes"><a class="anchor" href="#v0_23_0_breaking_changes"></a><a class="link" href="#v0_23_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>memfs: refactoring, allow multiple instances of memfs in single package</p>
-<div class="paragraph">
-<p>Previously, the generated Go code from memfs can be used only once
-on the package that use it. For example, if we have two instances of
-memfs.MemFS and both of them call GoGenerate(), when we load them back
-again only the last one will be active and set the global variable
-memfs.GeneratedPathNode.</p>
-</div>
-<div class="paragraph">
-<p>This changes refactoring on how we use memfs by storing the
-generated path node into variable that is defined by user and pass
-them to New Options.</p>
-</div>
-</li>
-<li>
-<p>memfs: remove field WithContent</p>
-<div class="paragraph">
-<p>The field WithContent is not necessary if we set MaxFileSize to negative
-value.</p>
-</div>
-</li>
-<li>
-<p>http: embed the memfs.Options into ServerOptions</p>
-<div class="paragraph">
-<p>This is to minimize duplicate on fields names and give clear distinction
-between options for Server and options for serving files on memory using
-memfs.</p>
-</div>
-</li>
-<li>
-<p>io: embed the memfs.Options into DirWatcher</p>
-<div class="paragraph">
-<p>This is to minimize duplicate configuration between DirWatcher and
-memfs, and to allow clear distinction between which options that
-affect the directory tree and options for DirWatcher.</p>
-</div>
-</li>
-<li>
-<p>memfs: allow AddFile to set internal path</p>
-<div class="paragraph">
-<p>Previously, AddFile set the internal path equal to path of file to be
-included. This may cause conflict if the file is already included
-due to the same sys path but different internal path.</p>
-</div>
-<div class="paragraph">
-<p>This commit add parameter internalPath to set custom internal path in
-the memfs map.</p>
-</div>
-</li>
-<li>
-<p>memfs: refactoring Go generate code to use memfs.MemFS instance</p>
-<div class="paragraph">
-<p>Instead of using memfs.PathNode, which is confusing for new user
-(what is PathNode?), we actually can use memfs.MemFS instance.</p>
-</div>
-<div class="paragraph">
-<p>This effect on how we use memfs in http package.</p>
-</div>
-</li>
-<li>
-<p>dns: change the SOA field in ZoneFile to non-pointer</p>
-<div class="paragraph">
-<p>The reason we use pointer for SOA record is so we can save them only
-if its not nil. A nil SOA record cause the generated JSON become "null"
-and this is make the consumer of ZoneFile do more work, checking for the
-null and initialize it when required.</p>
-</div>
-<div class="paragraph">
-<p>This changes, make the SOA record to non-nil and we save the record only
-if the MName field is not empty.</p>
-</div>
-</li>
-<li>
-<p>dns: replace master word with zone</p>
-<div class="paragraph">
-<p>This is for consistency for type and variable names.</p>
-</div>
-</li>
-<li>
-<p>sql: sort returned names on ExtractSQLFields sorted in ascending</p>
-<div class="paragraph">
-<p>This is to make sure that any test that use the package always
-predictable.</p>
-</div>
-<div class="paragraph">
-<p>While at it, add paramter to change placeholder on ExtractSQLFields.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_23_0_new_features"><a class="anchor" href="#v0_23_0_new_features"></a><a class="link" href="#v0_23_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: add method Post on client</p>
-<div class="paragraph">
-<p>The Post method send the POST request to path without setting
-"Content-Type".</p>
-</div>
-</li>
-<li>
-<p>lib/clise: new package that implement circular slice</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>A circular slice is a slice that have fixed size.
-An append to slice that has reached its length will overwrite and start
-again from index 0.</p>
-</div>
-<div class="paragraph">
-<p>For example, a clise with size 5,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>c := clise.New(5)
-c.Push(1, 2, 3, 4, 5)
-fmt.Printf("%v\n", c.Slice()) // [1 2 3 4 5]</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>If we push another item, it will overwrite the first index,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>c.Push(6)
-fmt.Printf("%v\n", c.Slice()) // [6 2 3 4 5]</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>See the examples for usage of the package.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>time: add function UnixMicro that return UNIX time in micro seconds</p>
-</li>
-<li>
-<p>api/slack: simple API for sending message to Slack using only
-standard packages.</p>
-</li>
-<li>
-<p>runes: add function to inverse the slice of rune</p>
-<div class="paragraph">
-<p>The Inverse function reverse the order of slice of rune without
-allocating another slice.</p>
-</div>
-</li>
-<li>
-<p>big: add method Humanize</p>
-<div class="paragraph">
-<p>The Humanize method return the r as string with custom thousand and
-decimal separator.</p>
-</div>
-</li>
-<li>
-<p>big: add method to round fraction to nearest non-zero value</p>
-<div class="paragraph">
-<p>The RoundNearestFraction does not require precision parameter, like in
-other rounds function, but it figure it out based on the last non-zero
-value from fraction.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_23_0_enhancements"><a class="anchor" href="#v0_23_0_enhancements"></a><a class="link" href="#v0_23_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: change the error messages on ResourceRecord initAndInitialize</p>
-<div class="paragraph">
-<p>This change make the error message more readable and understandable by
-consumer</p>
-</div>
-</li>
-<li>
-<p>dns: add method to get list of non-local caches in the Server</p>
-<div class="paragraph">
-<p>The CachesLRU method return the list of non-local caches ordered by
-the least recently used.</p>
-</div>
-<div class="paragraph">
-<p>This changes affect the answer type which must be exported, including
-most of its fields, so consumer can access it.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_23_0_bug_fixes"><a class="anchor" href="#v0_23_0_bug_fixes"></a><a class="link" href="#v0_23_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>sql: check nil on Migrate parameter "fs" using reflect.IsNil</p>
-<div class="paragraph">
-<p>If we pass nil pointer of type to fs, the if condition will not true
-and this cause panic because fs is not nil.</p>
-</div>
-</li>
-<li>
-<p>http: fix the package documentation</p>
-<div class="paragraph">
-<p>The RegisterXxx methods on Server has been replaced with single method,
-RegisterEndpoint.</p>
-</div>
-</li>
-<li>
-<p>dns: fix saving the TXT record file on zone file</p>
-<div class="paragraph">
-<p>The TXT record value must be wrapped with quote when stored on zone
-file.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_22_0"><a class="anchor" href="#v0_22_0"></a><a class="link" href="#v0_22_0">share v0.22.0 (2021-01-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_22_0_breaking_changes"><a class="anchor" href="#v0_22_0_breaking_changes"></a><a class="link" href="#v0_22_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>contact: remove unused package proofn</p>
-</li>
-<li>
-<p>sql: change the new client function parameter into struct of options.</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_22_0_new_features"><a class="anchor" href="#v0_22_0_new_features"></a><a class="link" href="#v0_22_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>cmd: add new CLI "totp"</p>
-<div class="paragraph">
-<p>The totp is a program to generate Time-based One-time Password from
-secret key.</p>
-</div>
-</li>
-<li>
-<p>totp: add method to generate n number of passwords</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_22_0_enhancements"><a class="anchor" href="#v0_22_0_enhancements"></a><a class="link" href="#v0_22_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: print client request if debug value is equal or greater than 2.</p>
-<div class="paragraph">
-<p>If user set DEBUG environment variable or debug.Value to 2 or greater,
-the http Client will print the request (header and body) to the
-standard output.</p>
-</div>
-</li>
-<li>
-<p>ssh: print the private key file that has an error when generating signers</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_21_0"><a class="anchor" href="#v0_21_0"></a><a class="link" href="#v0_21_0">share v0.21.0 (2020-12-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_21_0_breaking_changes"><a class="anchor" href="#v0_21_0_breaking_changes"></a><a class="link" href="#v0_21_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>test: refactoring Assert with better error message</p>
-<div class="paragraph">
-<p>The new Assert function use the reflect.DoEqual that return an error
-which describe which field have unmatched value.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_21_0_new_features"><a class="anchor" href="#v0_21_0_new_features"></a><a class="link" href="#v0_21_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: allow Endpoint to register custom error handler</p>
-<div class="paragraph">
-<p>The new field ErrorHandler on Endpoint allow the implementor to define
-their own function to handler error from Endpoint.Call.</p>
-</div>
-<div class="paragraph">
-<p>If the ErrorHandler is nil it will default to DefaultErrorHandler.</p>
-</div>
-</li>
-<li>
-<p>totp: new package that implement TOTP protocol</p>
-<div class="paragraph">
-<p>Package totp implement Time-Based One-Time Password Algorithm based on
-RFC 6238.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_21_0_bug_fixes"><a class="anchor" href="#v0_21_0_bug_fixes"></a><a class="link" href="#v0_21_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>parser: fix Line method that always return non-empty line</p>
-<div class="paragraph">
-<p>In case of content end without new line, for example "anb", the Line()
-method always return "b, 0" on the last line.</p>
-</div>
-</li>
-<li>
-<p>smtp: update the expired test certificate</p>
-</li>
-<li>
-<p>websocket: create buffered channel for running queue.</p>
-<div class="paragraph">
-<p>This is to fix Stop() method waiting for running channel to be consumed.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_21_0_enhancements"><a class="anchor" href="#v0_21_0_enhancements"></a><a class="link" href="#v0_21_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>big: update the latest expected error message with Go tip</p>
-</li>
-<li>
-<p>http: add an example on how to write custom HTTP status code</p>
-<div class="paragraph">
-<p>The example show how to use http.ResponseWriter.WriteHeader to write
-custom HTTP status code instead of relying on errors.E.</p>
-</div>
-</li>
-<li>
-<p>net: always return the host name or IP on ParseIPPort.</p>
-<div class="paragraph">
-<p>Previously, if the address is an IP address the returned value is empty,
-for example "127.0.0.1" will return empty host but with non-nil IP and
-port.</p>
-</div>
-<div class="paragraph">
-<p>This changes always return the host either as host name (the same as
-paremeter) or valid IP address.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_21_0_chores"><a class="anchor" href="#v0_21_0_chores"></a><a class="link" href="#v0_21_0_chores">Chores</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>all: replace the tasks to serve and generate docs using ciigo as library</p>
-<div class="paragraph">
-<p>This way, one does not need to install ciigo binary, only require Go
-tools.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_20_1"><a class="anchor" href="#v0_20_1"></a><a class="link" href="#v0_20_1">share v0.20.1 (2020-11-08)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_20_1_bug_fixes"><a class="anchor" href="#v0_20_1_bug_fixes"></a><a class="link" href="#v0_20_1_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>websocket: set TLSConfig to nil if Endpoint scheme is not https or wss.</p>
-<div class="paragraph">
-<p>If user set TLSConfig but the Endpoint is not start with "https" or "wss",
-client open() method may return an error "Connect: tls: first record does
-not look like a TLS handshake".</p>
-</div>
-</li>
-<li>
-<p>paseto: add 5 seconds time drift when validating JSONToken</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_20_1_enhancements"><a class="anchor" href="#v0_20_1_enhancements"></a><a class="link" href="#v0_20_1_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>big: add method RoundToNearestAway and RoundToZero</p>
-<div class="paragraph">
-<p>RoundToNearestAway round r to n digit precision using nearest away mode,
-where mantissa is accumulated by the last digit after precision.
-For example, using 2 digit precision, 0.555 would become 0.56.</p>
-</div>
-<div class="paragraph">
-<p>RoundToZero round r to n digit precision using to zero mode.
-For example, using 2 digit precision, 0.555 would become 0.55.</p>
-</div>
-</li>
-<li>
-<p>parser: add Stop method</p>
-<div class="paragraph">
-<p>The Stop method return the remaining unparsed content and its last
-position, and then call Close to reset the internal state back to zero.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_20_1_chores"><a class="anchor" href="#v0_20_1_chores"></a><a class="link" href="#v0_20_1_chores">Chores</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>paseto: fix linter warnings</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_20_0"><a class="anchor" href="#v0_20_0"></a><a class="link" href="#v0_20_0">share v0.20.0 (2020-10-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_20_0_new_features"><a class="anchor" href="#v0_20_0_new_features"></a><a class="link" href="#v0_20_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/paseto: a simple, ready to use, implementation of Platform-Agnostic
-SEcurity TOkens</p>
-<div class="paragraph">
-<p>This implementation only support PASETO Protocol v2.</p>
-</div>
-<div class="paragraph">
-<p>This library focus on how to sign and verify data, everything else is
-handled and filled automatically.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_20_0_enhancements"><a class="anchor" href="#v0_20_0_enhancements"></a><a class="link" href="#v0_20_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: serve DoT without SSL if server is behind proxy or tlsConfig is null.</p>
-<div class="paragraph">
-<p>Previously we only check for tlsConfig, if its null the DoT server
-will not running.
-There is a use case where the SSL terminated by proxy and the connection
-is forwarded to DNS server, so this changes accommodated it.</p>
-</div>
-</li>
-<li>
-<p>http: increase the debug level from 2 to 3</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_19_0"><a class="anchor" href="#v0_19_0"></a><a class="link" href="#v0_19_0">share v0.19.0 (2020-09-08)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_19_0_breaking_changes"><a class="anchor" href="#v0_19_0_breaking_changes"></a><a class="link" href="#v0_19_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: unexport the Messsage&#8217;s Packet field</p>
-</li>
-<li>
-<p>dns: change the HostsFile Messages to list of ResourceRecord</p>
-</li>
-<li>
-<p>dns: unexport the master file path field</p>
-</li>
-<li>
-<p>dns: refactoring the ResourceRecord values from []byte to string</p>
-<div class="paragraph">
-<p>There are two reasons for this changes. First, to allow JSON encoded
-of ResourceRecord.Value without encoded to base64.</p>
-</div>
-<div class="paragraph">
-<p>Second, to minimize unreleased packet due to the backing storage is
-still used when assigned to Value (or any []byte field in RDataXXX).</p>
-</div>
-</li>
-<li>
-<p>dns: dns: split between MasterFile and masterParser</p>
-<div class="paragraph">
-<p>While at it add field Records that contains unpacked ResourceRecord as
-mapping between domain and ResourceRecord.</p>
-</div>
-<div class="paragraph">
-<p>This is useful for client that need to edit the RR in MasterFile.</p>
-</div>
-<div class="paragraph">
-<p>This changes also unexport the Messages field, to access it use the method
-Messages.</p>
-</div>
-</li>
-<li>
-<p>websocket: move the server handler to ServerOptions</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_19_0_new_features"><a class="anchor" href="#v0_19_0_new_features"></a><a class="link" href="#v0_19_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: add method to remove local caches by names on Server</p>
-</li>
-<li>
-<p>dns: add method to search caches</p>
-</li>
-<li>
-<p>dns: add method Delete to MasterFile</p>
-</li>
-<li>
-<p>dns: add method to remove RR from cache and master file</p>
-</li>
-<li>
-<p>dns: add method to save the master records to file</p>
-</li>
-<li>
-<p>dns: implement method to add new RR to master file</p>
-</li>
-<li>
-<p>dns: add method to update/insert resource record to caches</p>
-</li>
-<li>
-<p>dns: add method to initialize and validate ResourceRecord</p>
-</li>
-<li>
-<p>websocket: add server options to change the connect and status paths</p>
-<div class="paragraph">
-<p>Previously, there is only one option for server, the port where it will
-listen.</p>
-</div>
-<div class="paragraph">
-<p>This changes add option to change the connect path (default to "/"
-previously) and new path and handler for retrieving server status.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_19_0_bug_fixes"><a class="anchor" href="#v0_19_0_bug_fixes"></a><a class="link" href="#v0_19_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: fix parsing SOA resource record data from master file</p>
-</li>
-<li>
-<p>dns: stop all forwarders on Stop()</p>
-</li>
-<li>
-<p>http: write the HTTP status code after setting content-type on error</p>
-</li>
-<li>
-<p>ini: ignore the last empty line on unsetAll</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_18_0"><a class="anchor" href="#v0_18_0"></a><a class="link" href="#v0_18_0">share v0.18.0 (2020-08-06)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_18_0_breaking_changes"><a class="anchor" href="#v0_18_0_breaking_changes"></a><a class="link" href="#v0_18_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>big: add global flag MarshalJSONAsString</p>
-<div class="paragraph">
-<p>MarshalJSONAsString define the default return behaviour of MarshalJSON().
-If its true (the default) the returned JSON format will encapsulated in
-double quote, as string instead of as numeric.</p>
-</div>
-</li>
-<li>
-<p>dns: refactoring resource record fields</p>
-</li>
-<li>
-<p>http: do not return error based on response code</p>
-<div class="paragraph">
-<p>The error in doRequest should be about connection error, everything
-else should be handled by user.</p>
-</div>
-</li>
-<li>
-<p>http: allow setting response type when registering PUT</p>
-<div class="paragraph">
-<p>User of this library may want to return something and they will suprised
-if the library always set the response type to None.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_18_0_bug_fixes"><a class="anchor" href="#v0_18_0_bug_fixes"></a><a class="link" href="#v0_18_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: fix panic if Request.Form is not initialized on Endpoint.call</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_18_0_enhancements"><a class="anchor" href="#v0_18_0_enhancements"></a><a class="link" href="#v0_18_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: add method to create Message from hostname and list of addresses</p>
-</li>
-<li>
-<p>dns: add method to remove caches by names on Server</p>
-</li>
-<li>
-<p>http: add method Put for Client</p>
-</li>
-<li>
-<p>http: add method to convert RequestMethod to string</p>
-</li>
-<li>
-<p>parser: add method to get single line</p>
-</li>
-<li>
-<p>strings: add function to delete a value from slice of string</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_17_0"><a class="anchor" href="#v0_17_0"></a><a class="link" href="#v0_17_0">share v0.17.0 (2020-07-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_17_0_breaking_changes"><a class="anchor" href="#v0_17_0_breaking_changes"></a><a class="link" href="#v0_17_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: replace RDataText with plain []byte</p>
-</li>
-<li>
-<p>http: add parameter headers to client methods</p>
-</li>
-<li>
-<p>http: return the http.Response as the first parameter</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_17_0_bug_fixes"><a class="anchor" href="#v0_17_0_bug_fixes"></a><a class="link" href="#v0_17_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: initialize TLSClientConfig only if insecure is true</p>
-</li>
-<li>
-<p>io: truncate file on Copy</p>
-</li>
-<li>
-<p>websocket: fix race on pingTicker when stopping server</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_17_0_enhancements"><a class="anchor" href="#v0_17_0_enhancements"></a><a class="link" href="#v0_17_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: check for possible index.html file on getFSNode</p>
-</li>
-<li>
-<p>http: add method Delete</p>
-</li>
-<li>
-<p>http: add method Stop for HTTP server</p>
-</li>
-<li>
-<p>http: check the number of bytes written on ResponseWriter.Write</p>
-</li>
-<li>
-<p>http: log error if path not exist if debug value is set to 3 or greater</p>
-</li>
-<li>
-<p>smtp: check for EOF when receiving data from server</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_16_0"><a class="anchor" href="#v0_16_0"></a><a class="link" href="#v0_16_0">share v0.16.0 (2020-06-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_16_0_breaking_changes"><a class="anchor" href="#v0_16_0_breaking_changes"></a><a class="link" href="#v0_16_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: refactoring loading hosts and master files</p>
-<div class="paragraph">
-<p>Instead of as methods in Server, we detach the LoadHostDir and
-LostMasterDir into functions that return list of filename and their
-content.</p>
-</div>
-</li>
-<li>
-<p>dns: disable serving DoH and DoT if port is not set (0)</p>
-<div class="paragraph">
-<p>Previously, if HTTPPort or TLSPort is not set (0) we set it to default
-value and keep serving the DNS over HTTP and TLS. Sometimes, user may
-want to serve DNS over UDP only.</p>
-</div>
-<div class="paragraph">
-<p>This changes disable serving DNS over HTTP (DoH) and TLS (DoT) if port
-is not set, or 0.</p>
-</div>
-</li>
-<li>
-<p>email: rename ParseAddress function to ParseMailboxes</p>
-</li>
-<li>
-<p>http: add parameter "insecure" when creating new client</p>
-</li>
-<li>
-<p>ini: fix inconsistencies between empty string and boolean true</p>
-<div class="paragraph">
-<p>In Git specification, an empty variable is equal to boolean true.
-This cause inconsistency between empty string and boolean true.</p>
-</div>
-</li>
-<li>
-<p>memfs: simplify the API, add directory parameter to New</p>
-<div class="paragraph">
-<p>This changes add parameter directory to be mounted in New(), so user
-did not need to call Mount manually</p>
-</div>
-<div class="paragraph">
-<p>This cause the Mount method and its sibling, Unmount and IsMounted
-become unneeded, so we remove them.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_16_0_bug_fixes"><a class="anchor" href="#v0_16_0_bug_fixes"></a><a class="link" href="#v0_16_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>api/telegram/bot: fix request parameter on GetMyCommands</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_16_0_new_features"><a class="anchor" href="#v0_16_0_new_features"></a><a class="link" href="#v0_16_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>bytes: add function MergeSpaces</p>
-<div class="paragraph">
-<p>The function MergeSpaces will convert sequences of white space into
-single space ' '.</p>
-</div>
-</li>
-<li>
-<p>email: add methods to unmarshal/marshal Mailbox from/to JSON</p>
-</li>
-<li>
-<p>email: add function to parse single mailbox</p>
-</li>
-<li>
-<p>email: add function to create multipart text and HTML message</p>
-</li>
-<li>
-<p>http: support CORS with white list of origin and headers</p>
-</li>
-<li>
-<p>ini: add method UnsetAll to remove all variables in section and/or
-subsection that match with the key</p>
-</li>
-<li>
-<p>ini: add method to Unmarshal ini values to struct</p>
-</li>
-<li>
-<p>os/exec: new package to simplify the standard "os/exec"</p>
-<div class="paragraph">
-<p>New extension to standard package is function ParseCommandArgs() that
-receive input as string and return itas command and list of arguments.
-Unlike strings.Fields() which only separated the field by space,
-ParseCommandArgs can detect possible single, double, or back quotes.</p>
-</div>
-<div class="paragraph">
-<p>Another extension is Run() function that accept the string command
-to be executed and their standard output and error.</p>
-</div>
-</li>
-<li>
-<p>sql: add method to migrate database schema</p>
-<div class="paragraph">
-<p>The Migrate method migrate the database using list of SQL files inside
-a directory.
-Each SQL file in directory will be executed in alphabetical order based on
-the last state.</p>
-</div>
-<div class="paragraph">
-<p>The state of migration will be saved in table "_migration" with the SQL
-file name that has been executed and the timestamp.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_16_0_enhancements"><a class="anchor" href="#v0_16_0_enhancements"></a><a class="link" href="#v0_16_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>api/telegram/bot: delete webhook upon setting new webhook</p>
-</li>
-<li>
-<p>dns: do not load hidden hosts and master file</p>
-<div class="paragraph">
-<p>Previously, the LoadHostDir and LoadMasterDir load all files inside
-the directory without checking if its hidden (starting with dot) or not.</p>
-</div>
-<div class="paragraph">
-<p>This changes make the hidden file not loaded so one can disable it
-temporarily by prefixing it with dot.</p>
-</div>
-</li>
-<li>
-<p>ini: make the add method append the variable after existing same key</p>
-</li>
-<li>
-<p>memfs: make the Node Readdir works when calling from generated Go code</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, the Go generated code from call to GoGenerate() set only
-mapping of path to node. Calling Readdir() using http.File using</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>root, err := mfs.Open("/")
-fis, err := root.Readdir(0)</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>will return nil on fis.</p>
-</div>
-<div class="paragraph">
-<p>This changes add all child nodes to generated node.</p>
-</div>
-</div>
-</div>
-</li>
-<li>
-<p>websocket: allow "https" scheme on Client&#8217;s Endpoint</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_15_0"><a class="anchor" href="#v0_15_0"></a><a class="link" href="#v0_15_0">share v0.15.0 (2020-05-04)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_15_0_breaking_changes"><a class="anchor" href="#v0_15_0_breaking_changes"></a><a class="link" href="#v0_15_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>big: check for zero length slice of byte or string on toRat</p>
-</li>
-<li>
-<p>ssh: replace the ClientConfig with ConfigSection</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_15_0_new_features"><a class="anchor" href="#v0_15_0_new_features"></a><a class="link" href="#v0_15_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>ssh: implement SSH client configuration parser&#8201;&#8212;&#8201;ssh_config(5)</p>
-</li>
-<li>
-<p>api/telegram/bot: Go package for Telegram API Bot</p>
-</li>
-<li>
-<p>http: implement a simplified HTTP client</p>
-</li>
-<li>
-<p>net/html: new package to simplify the golang.org/x/net/html</p>
-<div class="paragraph">
-<p>The x/net/html package currently only provide bare raw functionalities
-to iterate tree, there is no check for empty node, no function to
-get attribute by name, and no simple way to iterate tree without looping it
-manually.</p>
-</div>
-<div class="paragraph">
-<p>This package extends the package by adding methods to get node&#8217;s attribute
-by name, get the first non-empty child, get the next non-empty sibling, and
-to iterate each node in the tree from top to bottom.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_15_0_enhancements"><a class="anchor" href="#v0_15_0_enhancements"></a><a class="link" href="#v0_15_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>big: return "0" instead of "&lt;nil&gt;" on Rat.String()</p>
-</li>
-<li>
-<p>big: return false if Rat is nil on IsGreaterThanZero</p>
-</li>
-<li>
-<p>http: add parameter to set default client&#8217;s headers</p>
-</li>
-<li>
-<p>websocket: add method to gracefully Close the client connection</p>
-</li>
-<li>
-<p>websocket: add routine that send PING control frame on Connect</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_15_0_bug_fixes"><a class="anchor" href="#v0_15_0_bug_fixes"></a><a class="link" href="#v0_15_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>reflect: remove checking for method IsEqual on type reflect.Ptr</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_14_0"><a class="anchor" href="#v0_14_0"></a><a class="link" href="#v0_14_0">share v0.14.0 (2020-04-03)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_14_0_breaking_changes"><a class="anchor" href="#v0_14_0_breaking_changes"></a><a class="link" href="#v0_14_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: simplify server Endpoint registrations</p>
-<div class="paragraph">
-<p>Previously, each endpoint with method DELETE, GET, PATCH, POST, and PUT
-require calling different call for registration. This change simplify
-it to one call only, "RegisterEndpoint", and the registration process
-will be handled automatically based on value on field Method.</p>
-</div>
-</li>
-<li>
-<p>mining/math: move the package from "lib/mining/" to "lib/" directory</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_14_0_new_features"><a class="anchor" href="#v0_14_0_new_features"></a><a class="link" href="#v0_14_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>debug: add a wrapper for starting and stopping CPU profile</p>
-</li>
-<li>
-<p>math/big: new package that extends the capabilities of "math/big"</p>
-<div class="paragraph">
-<p>The "big" package add custom global precision, rounding mode, and number
-of digit precision after decimal point for all instance of Float that
-use the package.</p>
-</div>
-</li>
-<li>
-<p>reflect: new package that extends the standard reflect</p>
-<div class="paragraph">
-<p>This package add new interface "Equaler", it is an interface that
-have single method "IsEqual()".</p>
-</div>
-<div class="paragraph">
-<p>Also, we have new function "IsNil(interface{})" that will return true
-if the value in interface{} is nil.</p>
-</div>
-</li>
-<li>
-<p>strings: add function SingleSpace</p>
-<div class="paragraph">
-<p>The SingleSpace function convert all sequences of white spaces into
-single space ' '.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_14_0_enhancements"><a class="anchor" href="#v0_14_0_enhancements"></a><a class="link" href="#v0_14_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: embed the standard http package instead of separate field</p>
-</li>
-<li>
-<p>hunspell: return the stem instead of root word on Spell() method</p>
-</li>
-<li>
-<p>hunspell: add Stem() method to Spell and Stem</p>
-<div class="paragraph">
-<p>The Stem() method reduce inflected (or sometimes derived) words to
-their word stem, base, or root form.</p>
-</div>
-</li>
-<li>
-<p>hunspell: add Analyze() method to Spell and Stem</p>
-<div class="paragraph">
-<p>The Analyze() method will return list of morphological fields of the
-word.</p>
-</div>
-</li>
-<li>
-<p>strings: check for other white spaces on MergeSpaces</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_14_0_bug_fixes"><a class="anchor" href="#v0_14_0_bug_fixes"></a><a class="link" href="#v0_14_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: fix the content-length header not set if file is not cached</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_13_0"><a class="anchor" href="#v0_13_0"></a><a class="link" href="#v0_13_0">share v0.13.0 (2020-03-11)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_13_0_breaking_changes"><a class="anchor" href="#v0_13_0_breaking_changes"></a><a class="link" href="#v0_13_0_breaking_changes">Breaking changes</a></h3>
-<div class="paragraph">
-<p>Set the minimum Go version to 1.13.</p>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_13_0_new_features"><a class="anchor" href="#v0_13_0_new_features"></a><a class="link" href="#v0_13_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>hunspell: a library to parse the Hunspell file format</p>
-</li>
-<li>
-<p>parser: provide a common text parser, using delimiters</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_13_0_enhancements"><a class="anchor" href="#v0_13_0_enhancements"></a><a class="link" href="#v0_13_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: use net.Addr for primary and fallback UDP/tCP addresses</p>
-</li>
-<li>
-<p>dns: change the mark of input/output in log output</p>
-</li>
-<li>
-<p>io: add function to copy file</p>
-</li>
-<li>
-<p>time: add functions to get Unix time in milliseconds (int64 and string)</p>
-</li>
-<li>
-<p>websocket: allow custom TLS configuration on client</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_13_0_bug_fixes"><a class="anchor" href="#v0_13_0_bug_fixes"></a><a class="link" href="#v0_13_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: fix handling server without fallback forwarder</p>
-</li>
-<li>
-<p>dns: check for nil DNS-over-TLS server on server&#8217;s Stop</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_12_0"><a class="anchor" href="#v0_12_0"></a><a class="link" href="#v0_12_0">share v0.12.0 (2020-02-13)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_12_0_breaking_changes"><a class="anchor" href="#v0_12_0_breaking_changes"></a><a class="link" href="#v0_12_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>bytes: move function JSONEscape and JSONUnescape to package json</p>
-</li>
-<li>
-<p>strings: move JSONEscape and JSONUnescape to package json</p>
-</li>
-<li>
-<p>time: change the Microsecond return type from int to int64</p>
-</li>
-<li>
-<p>websocket: change the RouteHandler signature to return Response</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_12_0_new_features"><a class="anchor" href="#v0_12_0_new_features"></a><a class="link" href="#v0_12_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>json: new packages to work with JSON</p>
-</li>
-<li>
-<p>sql: a new package as an extension to "database/sql"</p>
-</li>
-<li>
-<p>xmlrpc: new package for working with XML-RPC</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_12_0_enhancements"><a class="anchor" href="#v0_12_0_enhancements"></a><a class="link" href="#v0_12_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>strings: add function to reverse a string</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_12_0_bug_fixes"><a class="anchor" href="#v0_12_0_bug_fixes"></a><a class="link" href="#v0_12_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: fix index out of range when unpacking OPT RR</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_11_0"><a class="anchor" href="#v0_11_0"></a><a class="link" href="#v0_11_0">share v0.11.0 (2019-12-26)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_11_0_breaking_changes"><a class="anchor" href="#v0_11_0_breaking_changes"></a><a class="link" href="#v0_11_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: merge Start and Wait into ListenAndServe</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_11_0_new_features"><a class="anchor" href="#v0_11_0_new_features"></a><a class="link" href="#v0_11_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>memfs: implement http.FileSystem on MemFS</p>
-</li>
-<li>
-<p>memfs: implement http.File on Node</p>
-</li>
-<li>
-<p>memfs: implement os.FileInfo on Node</p>
-</li>
-<li>
-<p>memfs: implement io.Closer, io.Reader, and io.Seeker on Node</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_11_0_enhancements"><a class="anchor" href="#v0_11_0_enhancements"></a><a class="link" href="#v0_11_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: allocate raw packet on receive</p>
-</li>
-<li>
-<p>dns: log the number of pruned records</p>
-</li>
-<li>
-<p>errors: add field Name and err</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_11_0_bug_fixes"><a class="anchor" href="#v0_11_0_bug_fixes"></a><a class="link" href="#v0_11_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: split between read and write timeout for TCPClient</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_10_2"><a class="anchor" href="#v0_10_2"></a><a class="link" href="#v0_10_2">share v0.10.2 (2019-12-07)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_10_2_bug_fixes"><a class="anchor" href="#v0_10_2_bug_fixes"></a><a class="link" href="#v0_10_2_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: check for bad certificate when reading DoT request</p>
-</li>
-<li>
-<p>dns: fix the use of goroutine on runForwarders</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_10_1"><a class="anchor" href="#v0_10_1"></a><a class="link" href="#v0_10_1">share v0.10.1 (2019-12-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_10_1_bug_fixes"><a class="anchor" href="#v0_10_1_bug_fixes"></a><a class="link" href="#v0_10_1_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: close the connection if receiving zero packet on serveTCPClient</p>
-</li>
-<li>
-<p>dns: increase and decrease number of forwarders only for primary forwarders</p>
-</li>
-<li>
-<p>dns: make the stopper channel to be buffered</p>
-</li>
-<li>
-<p>dns: check for nil forwarder</p>
-</li>
-<li>
-<p>dns: check for nil connection on DoTClient&#8217;s Close</p>
-</li>
-<li>
-<p>dns: check for zero query type and class on TCPClient Lookup method</p>
-</li>
-<li>
-<p>dns: check for nil connection on Close at TCPClient</p>
-</li>
-<li>
-<p>dns: minimize double looping on checking error at serveTCPClient</p>
-</li>
-<li>
-<p>git: fix the test using full path URL and repository directory</p>
-</li>
-<li>
-<p>io: fix test using existing file instead of generate file</p>
-</li>
-<li>
-<p>net: handle interrupted system call on epoll Wait</p>
-</li>
-<li>
-<p>ssh: fix test ClientConfig initialize on Github Actions</p>
-</li>
-<li>
-<p>websocket: remove test for empty endpoint due to different format</p>
-</li>
-<li>
-<p>websocket: fix zero response ID when error on handleText</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_10_1_enhancements"><a class="anchor" href="#v0_10_1_enhancements"></a><a class="link" href="#v0_10_1_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: remove the use of pointer on Message fields</p>
-</li>
-<li>
-<p>dns: remove the use of ResourceRecord pool</p>
-</li>
-<li>
-<p>http: add method HTTPMethod to Endpoint</p>
-</li>
-<li>
-<p>http: disable creating Memfs if Root options is empty</p>
-</li>
-<li>
-<p>memfs: remove unneeded call to GeneratedPathNode.Set</p>
-</li>
-<li>
-<p>mining: move commands to root</p>
-</li>
-<li>
-<p>websocket: add examples of WebSocket as chat server and client</p>
-</li>
-<li>
-<p>websocket: add new function to create broadcast response</p>
-</li>
-<li>
-<p>websocket: add field Conn to represent connection in Request</p>
-</li>
-<li>
-<p>websocket: check for read timeout on recv</p>
-</li>
-<li>
-<p>websocket: remove unused error on NewServer</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_10_0"><a class="anchor" href="#v0_10_0"></a><a class="link" href="#v0_10_0">share v0.10.0 (2019-11-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_10_0_new_features"><a class="anchor" href="#v0_10_0_new_features"></a><a class="link" href="#v0_10_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: implement client and server for DNS over TLS</p>
-</li>
-<li>
-<p>ini: add method GetsUniq and ValsUniq that return uniq values only</p>
-</li>
-<li>
-<p>net: implement network polling using epoll and kqueue</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_10_0_breaking_changes"><a class="anchor" href="#v0_10_0_breaking_changes"></a><a class="link" href="#v0_10_0_breaking_changes">Breaking Changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: change the server certificate options to load from files</p>
-</li>
-<li>
-<p>ini: change Gets return as is, with duplicate values</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_10_0_enhancements"><a class="anchor" href="#v0_10_0_enhancements"></a><a class="link" href="#v0_10_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: allow listening on DoH without requiring certificate</p>
-</li>
-<li>
-<p>ini: support marshaling and un-marshaling time.Duration</p>
-</li>
-<li>
-<p>ini: support marshaling and un-marshaling time.Time</p>
-</li>
-<li>
-<p>ini: support marshaling and un-marshaling embedded structs</p>
-</li>
-<li>
-<p>websocket: websocket: replace epoll implementation with libnet.Poll</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_10_0_bug_fixes"><a class="anchor" href="#v0_10_0_bug_fixes"></a><a class="link" href="#v0_10_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: return error code 4 if server receive unknown message class or type</p>
-</li>
-<li>
-<p>dns: return an error if section question contains invalid packet</p>
-</li>
-<li>
-<p>ini: fix return value for empty string in IsValueBoolTrue</p>
-</li>
-<li>
-<p>strings: fix logic of Split function</p>
-</li>
-<li>
-<p>websocket: set the response ID after calling handler on handleText</p>
-</li>
-<li>
-<p>websocket: wrap the response with frame on sendResponse</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_9_0"><a class="anchor" href="#v0_9_0"></a><a class="link" href="#v0_9_0">share v0.9.0 (2019-10-08)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_9_0_new_features"><a class="anchor" href="#v0_9_0_new_features"></a><a class="link" href="#v0_9_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>bytes: add function to get all indexes of word in string</p>
-</li>
-<li>
-<p>bytes: add function to take snippets from string by indexes</p>
-</li>
-<li>
-<p>bytes: add function to get all indexes of token in string</p>
-</li>
-<li>
-<p>ints: add function to merge two slices by distance</p>
-</li>
-<li>
-<p>memfs: add method to add file directly as child of root</p>
-</li>
-<li>
-<p>memfs: add method to Search content of files</p>
-</li>
-<li>
-<p>sanitize: new package to sanitize markup document into plain text</p>
-<div class="paragraph">
-<p>Current implementation have a function to sanitize the content of HTML.</p>
-</div>
-</li>
-<li>
-<p>strings: add function to convert slice of string to slice of slice of bytes</p>
-</li>
-<li>
-<p>http: implement key binding in registered Endpoint&#8217;s Path</p>
-<div class="paragraph">
-<p>Previously, only raw path can be registered on Endpoint. This changes
-implement key binding using colon ":" on path. For example, registering
-path "/:x/y" will bind key "x" to a string value that can be accessed on
-http.Request.Form using Get method.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_9_0_breaking_changes"><a class="anchor" href="#v0_9_0_breaking_changes"></a><a class="link" href="#v0_9_0_breaking_changes">Breaking Changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>ini: set variable with "=" without a value default to empty string</p>
-<div class="openblock">
-<div class="content">
-<div class="paragraph">
-<p>Previously, a variable end with "=" will have value set to "true".
-For example,</p>
-</div>
-<div class="listingblock">
-<div class="content">
-<pre>[section]
-var =</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>set the "var" value to string "true".</p>
-</div>
-<div class="paragraph">
-<p>This changes make the variable that end with "=" without any value
-to be an empty string, so "var" value is equal to "".</p>
-</div>
-</div>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_9_0_bug_fixes"><a class="anchor" href="#v0_9_0_bug_fixes"></a><a class="link" href="#v0_9_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>ini: check for possible nil variable on Write</p>
-</li>
-<li>
-<p>dns: allow message with non recursive-desired to be forwarded</p>
-<div class="paragraph">
-<p>On macOS, turn out, all DNS queries have RD flag set to zero. This cause
-no DNS queries forwarded to parent server.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_9_0_enhancements"><a class="anchor" href="#v0_9_0_enhancements"></a><a class="link" href="#v0_9_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: export the Memfs field on Server</p>
-<div class="paragraph">
-<p>User of HTTP can use the Memfs field to get the content manually or
-to Search the content.</p>
-</div>
-</li>
-<li>
-<p>http: add content and response type HTML and XML</p>
-</li>
-<li>
-<p>memfs: export the Decode method on Node</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_8_2"><a class="anchor" href="#v0_8_2"></a><a class="link" href="#v0_8_2">share v0.8.2 (2019-09-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_8_2_enhancements"><a class="anchor" href="#v0_8_2_enhancements"></a><a class="link" href="#v0_8_2_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>http: make the request body always available even after ParseForm()</p>
-<div class="paragraph">
-<p>Previously, if the request type is query, form, or JSON, we call the
-ParseForm() to let the http.Request read the Body POST form data and fill
-the Form and/or PostForm fields. This method will cause the request
-Body will become empty since its already read and closed.
-One of use case of POST with form data is to check the integrity of POST
-body using checksum, which is not possible using only ParseForm().
-This commit read all the body first into reqBody and recreate the request
-Body back using ioutil.NopCloser and bytes.Buffer.</p>
-</div>
-</li>
-<li>
-<p>all: replace document generator from asciidoctor to ciigo</p>
-<div class="paragraph">
-<p>Previously, generating HTML files from asciidoc files require installing
-ruby, asciidoctor, and its dependency through Gemfile.
-To simplify this, we replace it with ciigo. Ciigo not only can convert
-the asciidoc files but it also support serving the file inside HTTP
-server and watching changes on asciidoc files during development for
-local previewing.</p>
-</div>
-</li>
-<li>
-<p>memfs: log and ignore error from NewNode</p>
-<div class="paragraph">
-<p>An error for calling NewNode should not stop processing all files
-in directory.</p>
-</div>
-</li>
-<li>
-<p>io: log and ignore error from NewNode</p>
-<div class="paragraph">
-<p>An error for calling NewNode should not stop processing all files
-in directory.</p>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_8_1"><a class="anchor" href="#v0_8_1"></a><a class="link" href="#v0_8_1">share v0.8.1 (2019-08-05)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_8_1_enhancements"><a class="anchor" href="#v0_8_1_enhancements"></a><a class="link" href="#v0_8_1_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>lib/ini: add functions to marshal/unmarshal bytes from/to struct.</p>
-<div class="paragraph">
-<p>The format to marshal/unmarshal ini stream is behave like JSON.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: add method to encode the content of file.</p>
-<div class="paragraph">
-<p>The ContentEncode() method encode each node&#8217;s content into specific
-encoding, in other words this method can be used to compress the content
-of file in memory before being served or written.
-Only file with size greater than 0 will be encoded.
-List of known encoding is "gzip".</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: ignore generated output filename on GoGenerate</p>
-<div class="paragraph">
-<p>In case the user Mount() the directory that include the generated output
-file, we want that file to be excluded from .go static source.</p>
-</div>
-</li>
-<li>
-<p>lib/memfs: set the Node Size to be zero if node is directory</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_8_0"><a class="anchor" href="#v0_8_0"></a><a class="link" href="#v0_8_0">share v0.8.0 (2019-07-09)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_8_0_breaking_changes"><a class="anchor" href="#v0_8_0_breaking_changes"></a><a class="link" href="#v0_8_0_breaking_changes">Breaking changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>All ASCII related contants and functions now being moved from <code>bytes</code>
-package to <code>ascii</code> package.</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_8_0_new_features"><a class="anchor" href="#v0_8_0_new_features"></a><a class="link" href="#v0_8_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>ascii: new library for working with ASCII characters</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_8_0_enhancements"><a class="anchor" href="#v0_8_0_enhancements"></a><a class="link" href="#v0_8_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: add method to restart forwarders</p>
-</li>
-<li>
-<p>dns: add fallback nameservers</p>
-</li>
-<li>
-<p>ini: create new section or variable if not exist on Set</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_7_0"><a class="anchor" href="#v0_7_0"></a><a class="link" href="#v0_7_0">share v0.7.0 (2019-06-14)</a></h2>
-<div class="sectionbody">
-<div class="paragraph">
-<p>This release bring major refactoring on <code>ini</code> package to provide a clean and
-simple API.</p>
-</div>
-<div class="sect2">
-<h3 id="v0_7_0_breaking_changes"><a class="anchor" href="#v0_7_0_breaking_changes"></a><a class="link" href="#v0_7_0_breaking_changes">Breaking Changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>ini: major refactoring</p>
-</li>
-<li>
-<p>net: add parameter to check Fully Qualified Domain Name on IsHostnameValid</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_7_0_new_features"><a class="anchor" href="#v0_7_0_new_features"></a><a class="link" href="#v0_7_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>spf: implementation of Sender Policy Framework (RFC 7208)</p>
-</li>
-<li>
-<p>ssh: package ssh provide a wrapper to golang.org/x/crypto/ssh</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_7_0_enhancements"><a class="anchor" href="#v0_7_0_enhancements"></a><a class="link" href="#v0_7_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>dns: add function to lookup PTR record by IP address</p>
-</li>
-<li>
-<p>dns: export Lookup method as part of Client interface</p>
-</li>
-<li>
-<p>doc: regenerate to use new style</p>
-</li>
-<li>
-<p>http: print the not-found path on Server&#8217;s getFSNode()</p>
-</li>
-<li>
-<p>ini: add method Vars that return all variables as map</p>
-</li>
-<li>
-<p>ini: add method to Rebase other INI object</p>
-</li>
-<li>
-<p>ini: add method to add, set, and unset variable</p>
-</li>
-<li>
-<p>ini: add method to convert key-value to map</p>
-</li>
-<li>
-<p>ini: add method to get section object by section and/or subsection name</p>
-</li>
-<li>
-<p>ini: add method to get variable values as slice of string</p>
-</li>
-<li>
-<p>ini: add method to prune INI variables</p>
-</li>
-<li>
-<p>ini: add methods to support templating</p>
-</li>
-<li>
-<p>io: add function to check if content of file is binary</p>
-</li>
-<li>
-<p>net: add function to check if IP address is IPv4 or IPv6</p>
-</li>
-<li>
-<p>net: add function to convert IPv6 into dot format</p>
-</li>
-<li>
-<p>ns: set log flag to 0, without time prefix</p>
-</li>
-<li>
-<p>strings: add function to append uniq values to slice of strings</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_7_0_bug_fixes"><a class="anchor" href="#v0_7_0_bug_fixes"></a><a class="link" href="#v0_7_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>io: watch changes on sub of sub directories on DirWatcher</p>
-</li>
-<li>
-<p>dns: substract the message TTL when the answer found on cache</p>
-</li>
-<li>
-<p>dns: always return true when answers RR exist and no TTL is zero</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_6_1"><a class="anchor" href="#v0_6_1"></a><a class="link" href="#v0_6_1">share v0.6.1 (2019-05-11)</a></h2>
-<div class="sectionbody">
-<div class="ulist">
-<ul>
-<li>
-<p><code>memfs</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>fix empty list names from MemFS created from GeneratedPathNode</p>
-</li>
-<li>
-<p>set root if GeneratedPathNode is not empty</p>
-</li>
-<li>
-<p>sort the generated file names</p>
-</li>
-<li>
-<p>fix template when generating empty content</p>
-</li>
-</ul>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_6_0"><a class="anchor" href="#v0_6_0"></a><a class="link" href="#v0_6_0">share v0.6.0 (2019-05-07)</a></h2>
-<div class="sectionbody">
-<div class="paragraph">
-<p>This release bring major changes on dns package.
-Most notable changes are adding caches and query forwarding (recursion), and
-removing the server handler.</p>
-</div>
-<div class="sect2">
-<h3 id="v0_6_0_breaking_changes"><a class="anchor" href="#v0_6_0_breaking_changes"></a><a class="link" href="#v0_6_0_breaking_changes">Breaking Changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>dns</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>refactor server to use Start(), Wait(), and Stop()</p>
-</li>
-<li>
-<p>use direct certificate instance on ServerOptions</p>
-</li>
-<li>
-<p>rename Send to Write, and change the parameter type to slice of byte</p>
-</li>
-<li>
-<p>remove "elapsed" parameter on Message.IsExpired()</p>
-</li>
-<li>
-<p>unexport the Request type</p>
-</li>
-<li>
-<p>remove receiver interface</p>
-</li>
-<li>
-<p>unexport connection type</p>
-</li>
-<li>
-<p>remove unused address parameter on client&#8217;s Query()</p>
-</li>
-<li>
-<p>unexport all fields from UDP and TCP clients</p>
-</li>
-<li>
-<p>remove TCPPort on ServerOptions</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>http</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>change server initialization using options</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>io</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>simplify Watcher to use callback instead of channel</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>memfs</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>refactoring go generate file to use type from memfs</p>
-</li>
-</ul>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_6_0_new_features"><a class="anchor" href="#v0_6_0_new_features"></a><a class="link" href="#v0_6_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>crypto</code>: new package that provide a wrapper for standard crypto library</p>
-</li>
-<li>
-<p><code>dns</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add caches to server</p>
-</li>
-<li>
-<p>add method to set AA, Query, RD, RCode on Message</p>
-</li>
-<li>
-<p>add mapping of response code to human readable names</p>
-</li>
-<li>
-<p>implement recursion, forwarding request to parent name servers</p>
-</li>
-<li>
-<p>check for zero TTL on authorities and additionals RR on IsExpired</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>io</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>implement naive directory change notification, DirWatcher</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>memfs</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add parameter to make reading file content become optional</p>
-</li>
-<li>
-<p>add method to unmount directory</p>
-</li>
-<li>
-<p>add method to check if memfs contains mounted directory</p>
-</li>
-<li>
-<p>add method to update node content and information</p>
-</li>
-<li>
-<p>export the method to add new child</p>
-</li>
-<li>
-<p>add method to remove child from any node</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>smtp</code>: add field DKIMOptions to Domain</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_6_0_bug_fixes"><a class="anchor" href="#v0_6_0_bug_fixes"></a><a class="link" href="#v0_6_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>dns</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>fix data race issue when running test</p>
-</li>
-<li>
-<p>set the TTL offset when packing resource record</p>
-</li>
-<li>
-<p>fix parsing TXT from zone file</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>http</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>allow serving directory with slash</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>memfs</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>fix possible invalid system path on file with symbolic link</p>
-</li>
-<li>
-<p>refresh the directory tree in Development mode if page not found</p>
-</li>
-</ul>
-</div>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_6_0_documentation"><a class="anchor" href="#v0_6_0_documentation"></a><a class="link" href="#v0_6_0_documentation">Documentation</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>add documentation for Sender Policy Framework (RFC 7208)</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_5_0"><a class="anchor" href="#v0_5_0"></a><a class="link" href="#v0_5_0">share v0.5.0 (2019-04-02)</a></h2>
-<div class="sectionbody">
-<div class="paragraph">
-<p>This minor release is dedicated for websocket package. Major refactoring on
-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="v0_5_0_new_features"><a class="anchor" href="#v0_5_0_new_features"></a><a class="link" href="#v0_5_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>cmd/smtpcli</code>: command line interface to SMTP client protocol</p>
-</li>
-<li>
-<p><code>ints</code>: new package for working with slice of integer</p>
-</li>
-<li>
-<p><code>ints64</code>: new package for working with slice of 64 bit integer</p>
-</li>
-<li>
-<p><code>floats64</code>: new package for working with slice of 64 bit float</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_5_0_enhancements"><a class="anchor" href="#v0_5_0_enhancements"></a><a class="link" href="#v0_5_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>bytes</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>change the Copy return type to non pointer</p>
-</li>
-<li>
-<p>add function to concat slice of byte or string into []byte</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>ints</code>: add function to remove value from slice</p>
-</li>
-<li>
-<p><code>websockets</code>:</p>
-<div class="ulist">
-<ul>
-<li>
-<p>Rewrite most of client and server APIs to be more simple and pass autobahn
-testsuite</p>
-</li>
-<li>
-<p>Minimize global variables and unexport internal constants and functions</p>
-</li>
-<li>
-<p>Handle interjected PING control frame from server</p>
-</li>
-<li>
-<p>Generate random mask only if masked field is set</p>
-</li>
-</ul>
-</div>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_4_0"><a class="anchor" href="#v0_4_0"></a><a class="link" href="#v0_4_0">share v0.4.0 (2019-03-01)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_4_0_new_features"><a class="anchor" href="#v0_4_0_new_features"></a><a class="link" href="#v0_4_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>email</code>: new package for working with Internet Message Format (RFC 5322)</p>
-</li>
-<li>
-<p><code>email/dkim</code>: new package for parsing and creating DKIM signature
-(RFC 6376)</p>
-</li>
-<li>
-<p><code>email/maildir</code>: new package to manage email using maildir format</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_4_0_enhancements"><a class="anchor" href="#v0_4_0_enhancements"></a><a class="link" href="#v0_4_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>bytes</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add function to copy slice</p>
-</li>
-<li>
-<p>add function to convert hexadecimal into byte</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>dns</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add mapping of connection types and its names</p>
-</li>
-<li>
-<p>print the section question type by string</p>
-</li>
-<li>
-<p>add method to filter Message.Answer by specific query type</p>
-</li>
-<li>
-<p>add pool for UDP client</p>
-</li>
-<li>
-<p>add function to get list of system name servers</p>
-</li>
-<li>
-<p>make UDPClient Query routine safe</p>
-</li>
-<li>
-<p>increase the internal debug level from 2 to 3</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>http</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add the charset type to content-type "text/plain"</p>
-</li>
-<li>
-<p>listen and serve using TLS if TLSConfig is defined</p>
-</li>
-<li>
-<p>add method to temporary redirect request to other location</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>ini</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>unexport the reader</p>
-</li>
-<li>
-<p>add method to get all variable values with the same key</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>io</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>rename Reader SkipSpace to SkipSpaces</p>
-</li>
-<li>
-<p>refactoring, export all fields for easy access on Reader</p>
-</li>
-<li>
-<p>add method read one line with line feed</p>
-</li>
-<li>
-<p>add method to unread N characters on Reader</p>
-</li>
-<li>
-<p>optimize ReadUntil without append</p>
-</li>
-<li>
-<p>add method to return the rest of unreaded buffer on Reader</p>
-</li>
-<li>
-<p>return the character separator that found on SkipUntil</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>memfs</code>
-</p>
-<div class="ulist">
-<ul>
-<li>
-<p>add method to dump files as Go generated source</p>
-</li>
-<li>
-<p>add variable for allowing bypass file in memory</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>smtp</code> (work in progress)</p>
-<div class="ulist">
-<ul>
-<li>
-<p>rename StorageFile to LocalStorage</p>
-</li>
-<li>
-<p>implement server with local handler</p>
-</li>
-<li>
-<p>add prefix Mail to methods in Storage interface</p>
-</li>
-<li>
-<p>use different port between normal listener and TLS listener</p>
-</li>
-</ul>
-</div>
-</li>
-<li>
-<p><code>time</code>: add function to get micro seconds</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_4_0_bug_fixes"><a class="anchor" href="#v0_4_0_bug_fixes"></a><a class="link" href="#v0_4_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>all: fix the usage of "iota"</p>
-</li>
-<li>
-<p><code>dns</code>: fix creating new UDP/TCP client without port number</p>
-</li>
-<li>
-<p><code>memfs</code>: check for empty directory on Mount</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_3_0"><a class="anchor" href="#v0_3_0"></a><a class="link" href="#v0_3_0">share v0.3.0 (2019-02-01)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_3_0_features_changes"><a class="anchor" href="#v0_3_0_features_changes"></a><a class="link" href="#v0_3_0_features_changes">Features Changes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>lib/debug</code>: add function to write heap profile to file</p>
-</li>
-<li>
-<p><code>lib/debug</code>: add type to store relative and difference on memory heap</p>
-</li>
-<li>
-<p><code>lib/dns</code>: remove request pool</p>
-</li>
-<li>
-<p><code>lib/dns</code>: export the connection field on UDPClient</p>
-</li>
-<li>
-<p><code>lib/dns</code>: add type of connection</p>
-</li>
-<li>
-<p><code>lib/http</code>: add parameter http.ResponseWriter to Callback.</p>
-</li>
-<li>
-<p><code>lib/http</code>: the RegisterXxx functions now use the Endpoint type.</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_3_0_enhancements"><a class="anchor" href="#v0_3_0_enhancements"></a><a class="link" href="#v0_3_0_enhancements">Enhancements</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p>Various fixes suggested by linters</p>
-</li>
-<li>
-<p>doc: add four summary and notes about DKIM</p>
-</li>
-<li>
-<p>doc: add summary of Simple Authentication and Security Layer (SASL)</p>
-</li>
-<li>
-<p>doc: add summary on SMTP over TLS (RFC3207)</p>
-</li>
-<li>
-<p>doc: add notes for Internet Message Format (RFC 5322)</p>
-</li>
-<li>
-<p>doc: add documentation for SMTP and DSN</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_3_0_bug_fixes"><a class="anchor" href="#v0_3_0_bug_fixes"></a><a class="link" href="#v0_3_0_bug_fixes">Bug fixes</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>lib/git</code>: fix testdata and test input</p>
-</li>
-</ul>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_2_0"><a class="anchor" href="#v0_2_0"></a><a class="link" href="#v0_2_0">share v0.2.0 (2019-01-02)</a></h2>
-<div class="sectionbody">
-<div class="sect2">
-<h3 id="v0_2_0_new_features"><a class="anchor" href="#v0_2_0_new_features"></a><a class="link" href="#v0_2_0_new_features">New features</a></h3>
-<div class="ulist">
-<ul>
-<li>
-<p><code>lib/errors</code>, package errors provide a custom error with code.</p>
-</li>
-<li>
-<p><code>lib/http</code>, package http implement custom HTTP server with memory file
-system and simplified routing handler.</p>
-</li>
-</ul>
-</div>
-</div>
-<div class="sect2">
-<h3 id="v0_2_0_enhancements"><a class="anchor" href="#v0_2_0_enhancements"></a><a class="link" href="#v0_2_0_enhancements">Enhancements</a></h3>
-<div class="paragraph">
-<p>Fix warnings from linters.</p>
-</div>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="v0_1_0"><a class="anchor" href="#v0_1_0"></a><a class="link" href="#v0_1_0">share v0.1.0 (2018-11-29)</a></h2>
-<div class="sectionbody">
-<div class="paragraph">
-<p>The first release of <code>share</code> package contains one command line interface (CLI)
-and several libraries.</p>
-</div>
-<div class="paragraph">
-<p>The CLI is <code>gofmtcomment</code> to convert comment from <code>/**/</code> to <code>//</code>.</p>
-</div>
-<div class="paragraph">
-<p>The libraries are <code>bytes</code>, <code>contact</code>, <code>dns</code>, <code>dsv</code>, <code>ini</code>, <code>io</code>, <code>memfs</code>,
-<code>mining</code>, <code>net</code>, <code>numbers</code>, <code>runes</code>, <code>strings</code>, <code>tabula</code>, <code>test</code>, <code>text</code>,
-<code>time</code>, and <code>websocket</code>.</p>
-</div>
-<div class="paragraph">
-<p>Documentation for each package can be viewed at,</p>
-</div>
-<div class="literalblock">
-<div class="content">
-<pre>https://godoc.org/github.com/shuLhan/share</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>I hope it will be stay alive!</p>
-</div>
-</div>
-</div>
</div>
<div id="footer">
<div id="footer-text">
-Last updated 2022-05-31 21:54:29 +0700
+Last updated 2022-07-03 14:36:51 +0700
</div>
</div>
</div>
diff --git a/_doc/CHANGELOG_2018-2019.adoc b/_doc/CHANGELOG_2018-2019.adoc
new file mode 100644
index 00000000..1d5ef825
--- /dev/null
+++ b/_doc/CHANGELOG_2018-2019.adoc
@@ -0,0 +1,575 @@
+= Changelog from 2018 to 2019
+Shulhan <ms@kilabit.info>
+3 July 2022
+:toc:
+:sectanchors:
+:sectlinks:
+
+link:CHANGELOG.html[Latest changelog^].
+
+link:CHANGELOG_2021.html[Changelog in 2021^].
+This is changelog for share module since v0.22.0 until v0.32.0.
+
+link:CHANGELOG_2020.html[Changelog in 2020^].
+This is changelog for share module since v0.12.0 until v0.21.0.
+
+
+[#v0_11_0]
+== share v0.11.0 (2019-12-26)
+
+[#v0_11_0_breaking_changes]
+=== Breaking changes
+
+* dns: merge Start and Wait into ListenAndServe
+
+[#v0_11_0_new_features]
+=== New features
+
+* memfs: implement http.FileSystem on MemFS
+* memfs: implement http.File on Node
+* memfs: implement os.FileInfo on Node
+* memfs: implement io.Closer, io.Reader, and io.Seeker on Node
+
+[#v0_11_0_enhancements]
+=== Enhancements
+
+* dns: allocate raw packet on receive
+* dns: log the number of pruned records
+* errors: add field Name and err
+
+[#v0_11_0_bug_fixes]
+=== Bug fixes
+
+* dns: split between read and write timeout for TCPClient
+
+
+[#v0_10_2]
+== share v0.10.2 (2019-12-07)
+
+[#v0_10_2_bug_fixes]
+=== Bug fixes
+
+* dns: check for bad certificate when reading DoT request
+* dns: fix the use of goroutine on runForwarders
+
+
+[#v0_10_1]
+== share v0.10.1 (2019-12-05)
+
+[#v0_10_1_bug_fixes]
+=== Bug fixes
+
+* dns: close the connection if receiving zero packet on serveTCPClient
+* dns: increase and decrease number of forwarders only for primary forwarders
+* dns: make the stopper channel to be buffered
+* dns: check for nil forwarder
+* dns: check for nil connection on DoTClient's Close
+* dns: check for zero query type and class on TCPClient Lookup method
+* dns: check for nil connection on Close at TCPClient
+* dns: minimize double looping on checking error at serveTCPClient
+* git: fix the test using full path URL and repository directory
+* io: fix test using existing file instead of generate file
+* net: handle interrupted system call on epoll Wait
+* ssh: fix test ClientConfig initialize on Github Actions
+* websocket: remove test for empty endpoint due to different format
+* websocket: fix zero response ID when error on handleText
+
+[#v0_10_1_enhancements]
+=== Enhancements
+
+* dns: remove the use of pointer on Message fields
+* dns: remove the use of ResourceRecord pool
+* http: add method HTTPMethod to Endpoint
+* http: disable creating Memfs if Root options is empty
+* memfs: remove unneeded call to GeneratedPathNode.Set
+* mining: move commands to root
+* websocket: add examples of WebSocket as chat server and client
+* websocket: add new function to create broadcast response
+* websocket: add field Conn to represent connection in Request
+* websocket: check for read timeout on recv
+* websocket: remove unused error on NewServer
+
+[#v0_10_0]
+== share v0.10.0 (2019-11-05)
+
+[#v0_10_0_new_features]
+=== New features
+
+* dns: implement client and server for DNS over TLS
+* ini: add method GetsUniq and ValsUniq that return uniq values only
+* net: implement network polling using epoll and kqueue
+
+[#v0_10_0_breaking_changes]
+=== Breaking Changes
+
+* dns: change the server certificate options to load from files
+* ini: change Gets return as is, with duplicate values
+
+[#v0_10_0_enhancements]
+=== Enhancements
+
+* dns: allow listening on DoH without requiring certificate
+* ini: support marshaling and un-marshaling time.Duration
+* ini: support marshaling and un-marshaling time.Time
+* ini: support marshaling and un-marshaling embedded structs
+* websocket: websocket: replace epoll implementation with libnet.Poll
+
+[#v0_10_0_bug_fixes]
+=== Bug fixes
+
+* dns: return error code 4 if server receive unknown message class or type
+* dns: return an error if section question contains invalid packet
+* ini: fix return value for empty string in IsValueBoolTrue
+* strings: fix logic of Split function
+* websocket: set the response ID after calling handler on handleText
+* websocket: wrap the response with frame on sendResponse
+
+
+[#v0_9_0]
+== share v0.9.0 (2019-10-08)
+
+[#v0_9_0_new_features]
+=== New features
+
+* bytes: add function to get all indexes of word in string
+* bytes: add function to take snippets from string by indexes
+* bytes: add function to get all indexes of token in string
+* ints: add function to merge two slices by distance
+* memfs: add method to add file directly as child of root
+* memfs: add method to Search content of files
+* sanitize: new package to sanitize markup document into plain text
++
+Current implementation have a function to sanitize the content of HTML.
+
+* strings: add function to convert slice of string to slice of slice of bytes
+
+* http: implement key binding in registered Endpoint's Path
++
+Previously, only raw path can be registered on Endpoint. This changes
+implement key binding using colon ":" on path. For example, registering
+path "/:x/y" will bind key "x" to a string value that can be accessed on
+http.Request.Form using Get method.
+
+[#v0_9_0_breaking_changes]
+=== Breaking Changes
+
+* ini: set variable with "=" without a value default to empty string
++
+--
+Previously, a variable end with "=" will have value set to "true".
+For example,
+
+----
+[section]
+var =
+----
+
+set the "var" value to string "true".
+
+This changes make the variable that end with "=" without any value
+to be an empty string, so "var" value is equal to "".
+--
+
+[#v0_9_0_bug_fixes]
+=== Bug fixes
+
+* ini: check for possible nil variable on Write
+
+* dns: allow message with non recursive-desired to be forwarded
++
+On macOS, turn out, all DNS queries have RD flag set to zero. This cause
+no DNS queries forwarded to parent server.
+
+[#v0_9_0_enhancements]
+=== Enhancements
+
+* http: export the Memfs field on Server
++
+User of HTTP can use the Memfs field to get the content manually or
+to Search the content.
+
+* http: add content and response type HTML and XML
+
+* memfs: export the Decode method on Node
+
+
+[#v0_8_2]
+== share v0.8.2 (2019-09-05)
+
+[#v0_8_2_enhancements]
+=== Enhancements
+
+* http: make the request body always available even after ParseForm()
++
+Previously, if the request type is query, form, or JSON, we call the
+ParseForm() to let the http.Request read the Body POST form data and fill
+the Form and/or PostForm fields. This method will cause the request
+Body will become empty since its already read and closed.
+One of use case of POST with form data is to check the integrity of POST
+body using checksum, which is not possible using only ParseForm().
+This commit read all the body first into reqBody and recreate the request
+Body back using ioutil.NopCloser and bytes.Buffer.
+
+* all: replace document generator from asciidoctor to ciigo
++
+Previously, generating HTML files from asciidoc files require installing
+ruby, asciidoctor, and its dependency through Gemfile.
+To simplify this, we replace it with ciigo. Ciigo not only can convert
+the asciidoc files but it also support serving the file inside HTTP
+server and watching changes on asciidoc files during development for
+local previewing.
+
+* memfs: log and ignore error from NewNode
++
+An error for calling NewNode should not stop processing all files
+in directory.
+
+* io: log and ignore error from NewNode
++
+An error for calling NewNode should not stop processing all files
+in directory.
+
+
+[#v0_8_1]
+== share v0.8.1 (2019-08-05)
+
+[#v0_8_1_enhancements]
+=== Enhancements
+
+* lib/ini: add functions to marshal/unmarshal bytes from/to struct.
++
+The format to marshal/unmarshal ini stream is behave like JSON.
+
+* lib/memfs: add method to encode the content of file.
++
+The ContentEncode() method encode each node's content into specific
+encoding, in other words this method can be used to compress the content
+of file in memory before being served or written.
+Only file with size greater than 0 will be encoded.
+List of known encoding is "gzip".
+
+* lib/memfs: ignore generated output filename on GoGenerate
++
+In case the user Mount() the directory that include the generated output
+file, we want that file to be excluded from .go static source.
+
+* lib/memfs: set the Node Size to be zero if node is directory
+
+
+[#v0_8_0]
+== share v0.8.0 (2019-07-09)
+
+[#v0_8_0_breaking_changes]
+=== Breaking changes
+
+* All ASCII related contants and functions now being moved from `bytes`
+ package to `ascii` package.
+
+[#v0_8_0_new_features]
+=== New features
+
+* ascii: new library for working with ASCII characters
+
+[#v0_8_0_enhancements]
+=== Enhancements
+
+* dns: add method to restart forwarders
+* dns: add fallback nameservers
+* ini: create new section or variable if not exist on Set
+
+
+[#v0_7_0]
+== share v0.7.0 (2019-06-14)
+
+This release bring major refactoring on `ini` package to provide a clean and
+simple API.
+
+[#v0_7_0_breaking_changes]
+=== Breaking Changes
+
+* ini: major refactoring
+* net: add parameter to check Fully Qualified Domain Name on IsHostnameValid
+
+[#v0_7_0_new_features]
+=== New features
+
+* spf: implementation of Sender Policy Framework (RFC 7208)
+* ssh: package ssh provide a wrapper to golang.org/x/crypto/ssh
+
+[#v0_7_0_enhancements]
+=== Enhancements
+
+* dns: add function to lookup PTR record by IP address
+* dns: export Lookup method as part of Client interface
+* doc: regenerate to use new style
+* http: print the not-found path on Server's getFSNode()
+* ini: add method Vars that return all variables as map
+* ini: add method to Rebase other INI object
+* ini: add method to add, set, and unset variable
+* ini: add method to convert key-value to map
+* ini: add method to get section object by section and/or subsection name
+* ini: add method to get variable values as slice of string
+* ini: add method to prune INI variables
+* ini: add methods to support templating
+* io: add function to check if content of file is binary
+* net: add function to check if IP address is IPv4 or IPv6
+* net: add function to convert IPv6 into dot format
+* ns: set log flag to 0, without time prefix
+* strings: add function to append uniq values to slice of strings
+
+[#v0_7_0_bug_fixes]
+=== Bug fixes
+
+* io: watch changes on sub of sub directories on DirWatcher
+* dns: substract the message TTL when the answer found on cache
+* dns: always return true when answers RR exist and no TTL is zero
+
+
+[#v0_6_1]
+== share v0.6.1 (2019-05-11)
+
+* `memfs`:
+** fix empty list names from MemFS created from GeneratedPathNode
+** set root if GeneratedPathNode is not empty
+** sort the generated file names
+** fix template when generating empty content
+
+
+[#v0_6_0]
+== share v0.6.0 (2019-05-07)
+
+This release bring major changes on dns package.
+Most notable changes are adding caches and query forwarding (recursion), and
+removing the server handler.
+
+[#v0_6_0_breaking_changes]
+=== Breaking Changes
+
+* `dns`:
+** refactor server to use Start(), Wait(), and Stop()
+** use direct certificate instance on ServerOptions
+** rename Send to Write, and change the parameter type to slice of byte
+** remove "elapsed" parameter on Message.IsExpired()
+** unexport the Request type
+** remove receiver interface
+** unexport connection type
+** remove unused address parameter on client's Query()
+** unexport all fields from UDP and TCP clients
+** remove TCPPort on ServerOptions
+
+* `http`:
+** change server initialization using options
+
+* `io`:
+** simplify Watcher to use callback instead of channel
+
+* `memfs`:
+** refactoring go generate file to use type from memfs
+
+[#v0_6_0_new_features]
+=== New features
+
+* `crypto`: new package that provide a wrapper for standard crypto library
+
+* `dns`:
+** add caches to server
+** add method to set AA, Query, RD, RCode on Message
+** add mapping of response code to human readable names
+** implement recursion, forwarding request to parent name servers
+** check for zero TTL on authorities and additionals RR on IsExpired
+
+* `io`:
+** implement naive directory change notification, DirWatcher
+
+* `memfs`:
+** add parameter to make reading file content become optional
+** add method to unmount directory
+** add method to check if memfs contains mounted directory
+** add method to update node content and information
+** export the method to add new child
+** add method to remove child from any node
+
+* `smtp`: add field DKIMOptions to Domain
+
+[#v0_6_0_bug_fixes]
+=== Bug fixes
+
+* `dns`:
+** fix data race issue when running test
+** set the TTL offset when packing resource record
+** fix parsing TXT from zone file
+
+* `http`:
+** allow serving directory with slash
+
+* `memfs`:
+** fix possible invalid system path on file with symbolic link
+** refresh the directory tree in Development mode if page not found
+
+[#v0_6_0_documentation]
+=== Documentation
+
+* add documentation for Sender Policy Framework (RFC 7208)
+
+
+[#v0_5_0]
+== share v0.5.0 (2019-04-02)
+
+This minor release is dedicated for websocket package. Major refactoring on
+server and client API to make it easy and extensible. The websocket is now
+100% pass the autobahn testsuite (minus compression feature).
+
+[#v0_5_0_new_features]
+=== New features
+
+* `cmd/smtpcli`: command line interface to SMTP client protocol
+* `ints`: new package for working with slice of integer
+* `ints64`: new package for working with slice of 64 bit integer
+* `floats64`: new package for working with slice of 64 bit float
+
+[#v0_5_0_enhancements]
+=== Enhancements
+
+* `bytes`:
+** change the Copy return type to non pointer
+** add function to concat slice of byte or string into []byte
+
+* `ints`: add function to remove value from slice
+
+* `websockets`:
+** Rewrite most of client and server APIs to be more simple and pass autobahn
+ testsuite
+** Minimize global variables and unexport internal constants and functions
+** Handle interjected PING control frame from server
+** Generate random mask only if masked field is set
+
+
+[#v0_4_0]
+== share v0.4.0 (2019-03-01)
+
+[#v0_4_0_new_features]
+=== New features
+
+* `email`: new package for working with Internet Message Format (RFC 5322)
+* `email/dkim`: new package for parsing and creating DKIM signature
+ (RFC 6376)
+* `email/maildir`: new package to manage email using maildir format
+
+[#v0_4_0_enhancements]
+=== Enhancements
+
+* `bytes`
+** add function to copy slice
+** add function to convert hexadecimal into byte
+
+* `dns`
+** add mapping of connection types and its names
+** print the section question type by string
+** add method to filter Message.Answer by specific query type
+** add pool for UDP client
+** add function to get list of system name servers
+** make UDPClient Query routine safe
+** increase the internal debug level from 2 to 3
+
+* `http`
+** add the charset type to content-type "text/plain"
+** listen and serve using TLS if TLSConfig is defined
+** add method to temporary redirect request to other location
+
+* `ini`
+** unexport the reader
+** add method to get all variable values with the same key
+
+* `io`
+** rename Reader SkipSpace to SkipSpaces
+** refactoring, export all fields for easy access on Reader
+** add method read one line with line feed
+** add method to unread N characters on Reader
+** optimize ReadUntil without append
+** add method to return the rest of unreaded buffer on Reader
+** return the character separator that found on SkipUntil
+
+* `memfs`
+** add method to dump files as Go generated source
+** add variable for allowing bypass file in memory
+
+* `smtp` (work in progress)
+** rename StorageFile to LocalStorage
+** implement server with local handler
+** add prefix Mail to methods in Storage interface
+** use different port between normal listener and TLS listener
+
+* `time`: add function to get micro seconds
+
+[#v0_4_0_bug_fixes]
+=== Bug fixes
+
+* all: fix the usage of "iota"
+* `dns`: fix creating new UDP/TCP client without port number
+* `memfs`: check for empty directory on Mount
+
+
+[#v0_3_0]
+== share v0.3.0 (2019-02-01)
+
+[#v0_3_0_features_changes]
+=== Features Changes
+
+* `lib/debug`: add function to write heap profile to file
+* `lib/debug`: add type to store relative and difference on memory heap
+* `lib/dns`: remove request pool
+* `lib/dns`: export the connection field on UDPClient
+* `lib/dns`: add type of connection
+* `lib/http`: add parameter http.ResponseWriter to Callback.
+* `lib/http`: the RegisterXxx functions now use the Endpoint type.
+
+[#v0_3_0_enhancements]
+=== Enhancements
+
+* Various fixes suggested by linters
+* doc: add four summary and notes about DKIM
+* doc: add summary of Simple Authentication and Security Layer (SASL)
+* doc: add summary on SMTP over TLS (RFC3207)
+* doc: add notes for Internet Message Format (RFC 5322)
+* doc: add documentation for SMTP and DSN
+
+[#v0_3_0_bug_fixes]
+=== Bug fixes
+
+* `lib/git`: fix testdata and test input
+
+
+[#v0_2_0]
+== share v0.2.0 (2019-01-02)
+
+[#v0_2_0_new_features]
+=== New features
+
+* `lib/errors`, package errors provide a custom error with code.
+
+* `lib/http`, package http implement custom HTTP server with memory file
+system and simplified routing handler.
+
+[#v0_2_0_enhancements]
+=== Enhancements
+
+Fix warnings from linters.
+
+
+[#v0_1_0]
+== share v0.1.0 (2018-11-29)
+
+The first release of `share` package contains one command line interface (CLI)
+and several libraries.
+
+The CLI is `gofmtcomment` to convert comment from `+/**/+` to `//`.
+
+The libraries are `bytes`, `contact`, `dns`, `dsv`, `ini`, `io`, `memfs`,
+`mining`, `net`, `numbers`, `runes`, `strings`, `tabula`, `test`, `text`,
+`time`, and `websocket`.
+
+Documentation for each package can be viewed at,
+
+ https://godoc.org/github.com/shuLhan/share
+
+I hope it will be stay alive!
diff --git a/_doc/CHANGELOG_2020.adoc b/_doc/CHANGELOG_2020.adoc
new file mode 100644
index 00000000..0908db64
--- /dev/null
+++ b/_doc/CHANGELOG_2020.adoc
@@ -0,0 +1,581 @@
+= Changelog 2020
+Shulhan <ms@kilabit.info>
+3 July 2022
+:toc:
+:sectanchors:
+:sectlinks:
+
+link:CHANGELOG.html[Latest changelog^].
+
+link:CHANGELOG_2021.html[Changelog in 2021^].
+This is changelog for share module since v0.22.0 until v0.32.0.
+
+link:CHANGELOG_2020.html[Changelog in 2020 (this document)^].
+This is changelog for share module since v0.12.0 until v0.21.0.
+
+link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^].
+This is changelog for share module since v0.1.0 until v0.11.0.
+
+
+[#v0_21_0]
+== share v0.21.0 (2020-12-06)
+
+[#v0_21_0_breaking_changes]
+=== Breaking changes
+
+* test: refactoring Assert with better error message
++
+The new Assert function use the reflect.DoEqual that return an error
+which describe which field have unmatched value.
+
+[#v0_21_0_new_features]
+=== New features
+
+* http: allow Endpoint to register custom error handler
++
+The new field ErrorHandler on Endpoint allow the implementor to define
+their own function to handler error from Endpoint.Call.
++
+If the ErrorHandler is nil it will default to DefaultErrorHandler.
+
+* totp: new package that implement TOTP protocol
++
+Package totp implement Time-Based One-Time Password Algorithm based on
+RFC 6238.
+
+[#v0_21_0_bug_fixes]
+=== Bug fixes
+
+* parser: fix Line method that always return non-empty line
++
+In case of content end without new line, for example "a\nb", the Line()
+method always return "b, 0" on the last line.
+
+* smtp: update the expired test certificate
+
+* websocket: create buffered channel for running queue.
++
+This is to fix Stop() method waiting for running channel to be consumed.
+
+[#v0_21_0_enhancements]
+=== Enhancements
+
+* big: update the latest expected error message with Go tip
+
+* http: add an example on how to write custom HTTP status code
++
+The example show how to use http.ResponseWriter.WriteHeader to write
+custom HTTP status code instead of relying on errors.E.
+
+* net: always return the host name or IP on ParseIPPort.
++
+Previously, if the address is an IP address the returned value is empty,
+for example "127.0.0.1" will return empty host but with non-nil IP and
+port.
++
+This changes always return the host either as host name (the same as
+paremeter) or valid IP address.
+
+[#v0_21_0_chores]
+=== Chores
+
+* all: replace the tasks to serve and generate docs using ciigo as library
++
+This way, one does not need to install ciigo binary, only require Go
+tools.
+
+
+[#v0_20_1]
+== share v0.20.1 (2020-11-08)
+
+[#v0_20_1_bug_fixes]
+=== Bug fixes
+
+* websocket: set TLSConfig to nil if Endpoint scheme is not https or wss.
++
+If user set TLSConfig but the Endpoint is not start with "https" or "wss",
+client open() method may return an error "Connect: tls: first record does
+not look like a TLS handshake".
+
+* paseto: add 5 seconds time drift when validating JSONToken
+
+[#v0_20_1_enhancements]
+=== Enhancements
+
+* big: add method RoundToNearestAway and RoundToZero
++
+RoundToNearestAway round r to n digit precision using nearest away mode,
+where mantissa is accumulated by the last digit after precision.
+For example, using 2 digit precision, 0.555 would become 0.56.
++
+RoundToZero round r to n digit precision using to zero mode.
+For example, using 2 digit precision, 0.555 would become 0.55.
+
+* parser: add Stop method
++
+The Stop method return the remaining unparsed content and its last
+position, and then call Close to reset the internal state back to zero.
+
+[#v0_20_1_chores]
+=== Chores
+
+* paseto: fix linter warnings
+
+
+[#v0_20_0]
+== share v0.20.0 (2020-10-05)
+
+[#v0_20_0_new_features]
+=== New features
+
+* lib/paseto: a simple, ready to use, implementation of Platform-Agnostic
+ SEcurity TOkens
++
+This implementation only support PASETO Protocol v2.
++
+This library focus on how to sign and verify data, everything else is
+handled and filled automatically.
+
+[#v0_20_0_enhancements]
+=== Enhancements
+
+* dns: serve DoT without SSL if server is behind proxy or tlsConfig is null.
++
+Previously we only check for tlsConfig, if its null the DoT server
+will not running.
+There is a use case where the SSL terminated by proxy and the connection
+is forwarded to DNS server, so this changes accommodated it.
+
+* http: increase the debug level from 2 to 3
+
+
+[#v0_19_0]
+== share v0.19.0 (2020-09-08)
+
+[#v0_19_0_breaking_changes]
+=== Breaking changes
+
+* dns: unexport the Messsage's Packet field
+
+* dns: change the HostsFile Messages to list of ResourceRecord
+
+* dns: unexport the master file path field
+
+* dns: refactoring the ResourceRecord values from []byte to string
++
+There are two reasons for this changes. First, to allow JSON encoded
+of ResourceRecord.Value without encoded to base64.
++
+Second, to minimize unreleased packet due to the backing storage is
+still used when assigned to Value (or any []byte field in RDataXXX).
+
+* dns: dns: split between MasterFile and masterParser
++
+While at it add field Records that contains unpacked ResourceRecord as
+mapping between domain and ResourceRecord.
++
+This is useful for client that need to edit the RR in MasterFile.
++
+This changes also unexport the Messages field, to access it use the method
+Messages.
+
+* websocket: move the server handler to ServerOptions
+
+[#v0_19_0_new_features]
+=== New features
+
+* dns: add method to remove local caches by names on Server
+
+* dns: add method to search caches
+
+* dns: add method Delete to MasterFile
+
+* dns: add method to remove RR from cache and master file
+
+* dns: add method to save the master records to file
+
+* dns: implement method to add new RR to master file
+
+* dns: add method to update/insert resource record to caches
+
+* dns: add method to initialize and validate ResourceRecord
+
+* websocket: add server options to change the connect and status paths
++
+Previously, there is only one option for server, the port where it will
+listen.
++
+This changes add option to change the connect path (default to "/"
+previously) and new path and handler for retrieving server status.
+
+[#v0_19_0_bug_fixes]
+=== Bug fixes
+
+* dns: fix parsing SOA resource record data from master file
+
+* dns: stop all forwarders on Stop()
+
+* http: write the HTTP status code after setting content-type on error
+
+* ini: ignore the last empty line on unsetAll
+
+
+[#v0_18_0]
+== share v0.18.0 (2020-08-06)
+
+[#v0_18_0_breaking_changes]
+=== Breaking changes
+
+* big: add global flag MarshalJSONAsString
++
+MarshalJSONAsString define the default return behaviour of MarshalJSON().
+If its true (the default) the returned JSON format will encapsulated in
+double quote, as string instead of as numeric.
+
+* dns: refactoring resource record fields
+
+* http: do not return error based on response code
++
+The error in doRequest should be about connection error, everything
+else should be handled by user.
+
+* http: allow setting response type when registering PUT
++
+User of this library may want to return something and they will suprised
+if the library always set the response type to None.
+
+[#v0_18_0_bug_fixes]
+=== Bug fixes
+
+* http: fix panic if Request.Form is not initialized on Endpoint.call
+
+[#v0_18_0_enhancements]
+=== Enhancements
+
+* dns: add method to create Message from hostname and list of addresses
+
+* dns: add method to remove caches by names on Server
+
+* http: add method Put for Client
+
+* http: add method to convert RequestMethod to string
+
+* parser: add method to get single line
+
+* strings: add function to delete a value from slice of string
+
+
+[#v0_17_0]
+== share v0.17.0 (2020-07-05)
+
+[#v0_17_0_breaking_changes]
+=== Breaking changes
+
+* dns: replace RDataText with plain []byte
+
+* http: add parameter headers to client methods
+
+* http: return the http.Response as the first parameter
+
+[#v0_17_0_bug_fixes]
+=== Bug fixes
+
+* http: initialize TLSClientConfig only if insecure is true
+
+* io: truncate file on Copy
+
+* websocket: fix race on pingTicker when stopping server
+
+[#v0_17_0_enhancements]
+=== Enhancements
+
+* http: check for possible index.html file on getFSNode
+
+* http: add method Delete
+
+* http: add method Stop for HTTP server
+
+* http: check the number of bytes written on ResponseWriter.Write
+
+* http: log error if path not exist if debug value is set to 3 or greater
+
+* smtp: check for EOF when receiving data from server
+
+
+[#v0_16_0]
+== share v0.16.0 (2020-06-05)
+
+[#v0_16_0_breaking_changes]
+=== Breaking changes
+
+* dns: refactoring loading hosts and master files
++
+Instead of as methods in Server, we detach the LoadHostDir and
+LostMasterDir into functions that return list of filename and their
+content.
+
+* dns: disable serving DoH and DoT if port is not set (0)
++
+Previously, if HTTPPort or TLSPort is not set (0) we set it to default
+value and keep serving the DNS over HTTP and TLS. Sometimes, user may
+want to serve DNS over UDP only.
++
+This changes disable serving DNS over HTTP (DoH) and TLS (DoT) if port
+is not set, or 0.
+
+* email: rename ParseAddress function to ParseMailboxes
+
+* http: add parameter "insecure" when creating new client
+
+* ini: fix inconsistencies between empty string and boolean true
++
+In Git specification, an empty variable is equal to boolean true.
+This cause inconsistency between empty string and boolean true.
+
+* memfs: simplify the API, add directory parameter to New
++
+This changes add parameter directory to be mounted in New(), so user
+did not need to call Mount manually
++
+This cause the Mount method and its sibling, Unmount and IsMounted
+become unneeded, so we remove them.
+
+[#v0_16_0_bug_fixes]
+=== Bug fixes
+
+* api/telegram/bot: fix request parameter on GetMyCommands
+
+[#v0_16_0_new_features]
+=== New features
+
+* bytes: add function MergeSpaces
++
+The function MergeSpaces will convert sequences of white space into
+single space ' '.
+
+* email: add methods to unmarshal/marshal Mailbox from/to JSON
+* email: add function to parse single mailbox
+* email: add function to create multipart text and HTML message
+
+* http: support CORS with white list of origin and headers
+
+* ini: add method UnsetAll to remove all variables in section and/or
+ subsection that match with the key
+
+* ini: add method to Unmarshal ini values to struct
+
+* os/exec: new package to simplify the standard "os/exec"
++
+New extension to standard package is function ParseCommandArgs() that
+receive input as string and return itas command and list of arguments.
+Unlike strings.Fields() which only separated the field by space,
+ParseCommandArgs can detect possible single, double, or back quotes.
++
+Another extension is Run() function that accept the string command
+to be executed and their standard output and error.
+
+* sql: add method to migrate database schema
++
+The Migrate method migrate the database using list of SQL files inside
+a directory.
+Each SQL file in directory will be executed in alphabetical order based on
+the last state.
++
+The state of migration will be saved in table "_migration" with the SQL
+file name that has been executed and the timestamp.
+
+[#v0_16_0_enhancements]
+=== Enhancements
+
+* api/telegram/bot: delete webhook upon setting new webhook
+
+* dns: do not load hidden hosts and master file
++
+Previously, the LoadHostDir and LoadMasterDir load all files inside
+the directory without checking if its hidden (starting with dot) or not.
++
+This changes make the hidden file not loaded so one can disable it
+temporarily by prefixing it with dot.
+
+* ini: make the add method append the variable after existing same key
+
+* memfs: make the Node Readdir works when calling from generated Go code
++
+--
+Previously, the Go generated code from call to GoGenerate() set only
+mapping of path to node. Calling Readdir() using http.File using
+
+ root, err := mfs.Open("/")
+ fis, err := root.Readdir(0)
+
+will return nil on fis.
+
+This changes add all child nodes to generated node.
+--
+
+* websocket: allow "https" scheme on Client's Endpoint
+
+
+[#v0_15_0]
+== share v0.15.0 (2020-05-04)
+
+[#v0_15_0_breaking_changes]
+=== Breaking changes
+
+* big: check for zero length slice of byte or string on toRat
+* ssh: replace the ClientConfig with ConfigSection
+
+[#v0_15_0_new_features]
+=== New features
+
+* ssh: implement SSH client configuration parser -- ssh_config(5)
+* api/telegram/bot: Go package for Telegram API Bot
+* http: implement a simplified HTTP client
+
+* net/html: new package to simplify the golang.org/x/net/html
++
+The x/net/html package currently only provide bare raw functionalities
+to iterate tree, there is no check for empty node, no function to
+get attribute by name, and no simple way to iterate tree without looping it
+manually.
++
+This package extends the package by adding methods to get node's attribute
+by name, get the first non-empty child, get the next non-empty sibling, and
+to iterate each node in the tree from top to bottom.
+
+[#v0_15_0_enhancements]
+=== Enhancements
+
+* big: return "0" instead of "<nil>" on Rat.String()
+* big: return false if Rat is nil on IsGreaterThanZero
+* http: add parameter to set default client's headers
+* websocket: add method to gracefully Close the client connection
+* websocket: add routine that send PING control frame on Connect
+
+[#v0_15_0_bug_fixes]
+=== Bug fixes
+
+* reflect: remove checking for method IsEqual on type reflect.Ptr
+
+
+[#v0_14_0]
+== share v0.14.0 (2020-04-03)
+
+[#v0_14_0_breaking_changes]
+=== Breaking changes
+
+* http: simplify server Endpoint registrations
++
+Previously, each endpoint with method DELETE, GET, PATCH, POST, and PUT
+require calling different call for registration. This change simplify
+it to one call only, "RegisterEndpoint", and the registration process
+will be handled automatically based on value on field Method.
+
+* mining/math: move the package from "lib/mining/" to "lib/" directory
+
+[#v0_14_0_new_features]
+=== New features
+
+* debug: add a wrapper for starting and stopping CPU profile
+
+* math/big: new package that extends the capabilities of "math/big"
++
+The "big" package add custom global precision, rounding mode, and number
+of digit precision after decimal point for all instance of Float that
+use the package.
+
+* reflect: new package that extends the standard reflect
++
+This package add new interface "Equaler", it is an interface that
+have single method "IsEqual()".
++
+Also, we have new function "IsNil(interface{})" that will return true
+if the value in interface{} is nil.
+
+* strings: add function SingleSpace
++
+The SingleSpace function convert all sequences of white spaces into
+single space ' '.
+
+[#v0_14_0_enhancements]
+=== Enhancements
+
+* http: embed the standard http package instead of separate field
+
+* hunspell: return the stem instead of root word on Spell() method
+
+* hunspell: add Stem() method to Spell and Stem
++
+The Stem() method reduce inflected (or sometimes derived) words to
+their word stem, base, or root form.
+
+* hunspell: add Analyze() method to Spell and Stem
++
+The Analyze() method will return list of morphological fields of the
+word.
+
+* strings: check for other white spaces on MergeSpaces
+
+[#v0_14_0_bug_fixes]
+=== Bug fixes
+
+* http: fix the content-length header not set if file is not cached
+
+
+[#v0_13_0]
+== share v0.13.0 (2020-03-11)
+
+[#v0_13_0_breaking_changes]
+=== Breaking changes
+
+Set the minimum Go version to 1.13.
+
+[#v0_13_0_new_features]
+=== New features
+
+* hunspell: a library to parse the Hunspell file format
+* parser: provide a common text parser, using delimiters
+
+[#v0_13_0_enhancements]
+=== Enhancements
+
+* dns: use net.Addr for primary and fallback UDP/tCP addresses
+* dns: change the mark of input/output in log output
+* io: add function to copy file
+* time: add functions to get Unix time in milliseconds (int64 and string)
+* websocket: allow custom TLS configuration on client
+
+[#v0_13_0_bug_fixes]
+=== Bug fixes
+
+* dns: fix handling server without fallback forwarder
+* dns: check for nil DNS-over-TLS server on server's Stop
+
+
+[#v0_12_0]
+== share v0.12.0 (2020-02-13)
+
+[#v0_12_0_breaking_changes]
+=== Breaking changes
+
+* bytes: move function JSONEscape and JSONUnescape to package json
+* strings: move JSONEscape and JSONUnescape to package json
+* time: change the Microsecond return type from int to int64
+* websocket: change the RouteHandler signature to return Response
+
+[#v0_12_0_new_features]
+=== New features
+
+* json: new packages to work with JSON
+* sql: a new package as an extension to "database/sql"
+* xmlrpc: new package for working with XML-RPC
+
+[#v0_12_0_enhancements]
+=== Enhancements
+
+* strings: add function to reverse a string
+
+[#v0_12_0_bug_fixes]
+=== Bug fixes
+
+* dns: fix index out of range when unpacking OPT RR
diff --git a/_doc/CHANGELOG_2021.adoc b/_doc/CHANGELOG_2021.adoc
new file mode 100644
index 00000000..8918389c
--- /dev/null
+++ b/_doc/CHANGELOG_2021.adoc
@@ -0,0 +1,1598 @@
+= Changelog 2021
+Shulhan <ms@kilabit.info>
+3 July 2022
+:toc:
+:sectanchors:
+:sectlinks:
+
+link:CHANGELOG.html[Latest changelog^].
+
+link:CHANGELOG_2021.html[Changelog in 2021 (this document)^].
+This is changelog for share module since v0.22.0 until v0.32.0.
+
+link:CHANGELOG_2020.html[Changelog in 2020^].
+This is changelog for share module since v0.12.0 until v0.21.0.
+
+link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^].
+This is changelog for share module since v0.1.0 until v0.11.0.
+
+
+[#v0_32_0]
+== share v0.32.0 (2021-12-03)
+
+This release bring major changes and enhancements to package dns and math/big.
+
+[#v0_32_0_breaking_changes]
+=== Breaking changes
+
+* math/big: refactoring AddFloat to accept variadic interface{}
++
+--
+Previously, the AddFloat function only accept two interface parameters.
+
+This changes make the AddFloat to accept many interface parameters.
+--
+
+* math/big: refactor NewFloat to accept interface{} instead of float64 only
++
+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.
+
+* math/big: refactoring the Rat
++
+--
+The promise of this package is to provide the Rat type with RoundToZero
+and without panic.
+
+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.
+
+Another breaking changes are,
+
+* Humanize() with nil pointer receiver will return string "0"
+* Any IsXxx() methods with nil pointer receiver will return false
+* MarshalJSON() will nil pointer receiver will return "null" instead of
+ "0" now
+--
+
+* lib/dns: refactoring, change signature of client Lookup
++
+--
+Previously, Lookup() method on Client pass the question name, type, and
+class as parameters.
+
+This changes make those parameters into MessageQuestion.
+--
+
+* lib/dns: refactoring ZoneFile into Zone
++
+--
+Reason: A Zone is not always represented by file, it just that in this
+package, it is.
+
+This changes rename the type ZoneFile into Zone.
+--
+
+* lib/dns: refactoring message question
++
+--
+Previously the type for message question section SectionQuestion.
+
+This changes, rename the type to MessageQuestion.
+--
+
+* lib/dns: refactoring the section header
++
+--
+This changes rename the SectionHeader into MessageHeader.
+
+The pack() method is optimized with the following results,
+
+benchmark old ns/op new ns/op delta
+BenchmarkMessageHeader_pack-8 66.2 21.7 -67.31%
+
+benchmark old allocs new allocs delta
+BenchmarkMessageHeader_pack-8 3 1 -66.67%
+
+benchmark old bytes new bytes delta
+BenchmarkMessageHeader_pack-8 32 16 -50.00%
+
+The unpack() method is simplified by minimizing the if-condition.
+
+This changes also fix the pack and unpack OpCode for value other then 0,
+due to wrong shift value, 2 instead of 3.
+--
+
+* lib/dns: refactoring, introduce new type RecordClass
++
+--
+Previously, the record class is represented by uint16 using prefix
+QueryClassXxx.
+
+This changes make the record class to be an independent type, to make
+code more strict (prevent passing invalid value), and readable.
+--
+
+* lib/dns: refactoring, create type RecordType to represent type of RR
++
+--
+Previously, we use uint16 to represent type for ResourceRecord Type or
+Question type.
+
+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.
+
+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.
+--
+
+* lib/dns: remove the fallback name servers (NS) from server options
++
+--
+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.
+
+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.
+
+This changes remove the unnecessary and complex fallback NS from
+server.
+--
+
+[#v0_32_0_new_features]
+=== New features
+
+* lib/dns: add support to save and load caches to/from storage
++
+--
+The CachesSave method write the non-local answers into an io.Writer,
+encoded with gob.
+
+The CachesLoad method load the gob encoded answers from an io.Reader.
+--
+
+* lib/ssh: use agent defined by config or from environment variable
++
+--
+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.
+
+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.
+--
+
+* ssh/config: add support for section variable IdentityAgent
++
+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.
+
+[#v0_32_0_bug_fixes]
+=== Bug fixes
+
+* math/big: return nil on Quo and QuoRat instead of panic
++
+--
+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.
+
+This changes make it less intrusive, instead of panic we check for
+zero value and return nil immediately.
+--
+
+* lib/dns: do not cache truncated answer
++
+--
+Previously only answer with non-zero response code is ignored.
+
+This changes ignore also answer where response header is truncated.
+--
+
+[#v0_32_0_enhancements]
+=== Enhancements
+
+* lib/dns: realign all struct fields
++
+--
+Turns out the struct that we frequently used, answer and resource_record,
+is not optimized.
+
+ 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
+
+This changes reorder all structs field to save space in memory.
+--
+
+* lib/dns: make the TCP forwarders as complementary of UDP
++
+--
+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.
+
+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.
+--
+
+* lib/dns: use different packet between UDP and TCP messages
++
+--
+Previously, all packet size for reading and sending the message is
+fixed to 4096, even on UDP.
+
+This changes set the UDP packet size maximum to 512 bytes and others to
+4096 bytes.
+
+While at it, minimize copying packet if its not reusable inside a method.
+--
+
+
+[#v0_31_0]
+== share v0.31.0 (2021-11-04)
+
+[#v0_31_0_breaking_changes]
+=== Breaking changes
+
+* lib/memfs: move the embedded parameter to Options
++
+--
+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.
+
+This commit add new type EmbedOptions that contains the parameters
+for GoEmbed.
+
+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.
+--
+
+* lib/totp: make the New to accept only hash with SHA1, SHA256, or SHA512
++
+--
+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.
+
+This changes update the New function signature to accept defined
+type that can be set to SHA1, SHA256, or SHA512.
+--
+
+* lib/bytes: refactoring and cleaning up the bytes package
++
+--
+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.
+
+A breaking changes,
+
+* 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.
+
+Bug fixes,
+
+* PrintHex: fix print layout on the last line
+* ReadHexByte: fix possible index out of range
+* SkipAfterToken return -1 and false if no token found, as promised
+ in the comment, instead of the length of text.
+
+We move all unit test to example so we have test and example in the
+documentation at the same time.
+
+This changes make all test coverage 100%.
+--
+
+* lib/bytes: refactoring AppendXxx functions
++
+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.
+
+* lib/ascii: change signature of ToLower and ToUpper
++
+Using pointer to slice on method or function is not a Go idiom.
+It is created when I still new to Go.
+
+* lib/memfs: refactoring Node field V into Content
++
+--
+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.
+
+Now, after having more time writing Go, I prefer clarity over
+cleverity(?).
+--
+
+* lib/memfs: set the node modification time in embedded file
++
+--
+This changes set all node modification time in embedded files to
+the node modTime using Unix() and Nanosecond() values.
+
+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.
+--
+
+[#v0_31_0_new_features]
+=== New features
+
+* lib/ini: add function IsValidVarName
++
+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.
+
+* lib/memfs: set the node modification time in embedded file
++
+--
+This changes set all node modification time in embedded files to
+the node modTime using Unix() and Nanosecond() values.
+
+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.
+--
+
+* lib/io: add method String to FileState type
++
+The String method return the string representation of FileState.
+Usually used only for debugging.
+
+* lib/smtp: implement method Noop on Client
++
+--
+Noop send the NOOP command to server with optional message.
+
+On success, it will return response with Code 250, StatusOK.
+
+While at it fix double call to recv on Reset() method.
+--
+
+* lib/smtp: implement method Reset on Client
++
+--
+The Reset() method send the STMP RSET command to the server.
+
+This command clear the current buffer on MAIL, RCPT, and DATA, but not the
+EHLO/HELO buffer.
+
+On success, it will return response with Code 250, StatusOK.
+--
+
+[#v0_31_0_bug_fixes]
+=== Bug fixes
+
+* lib/ascii: fix IsHex return false on 0
+
+* lib/memfs: fix parent empty directory not removed
++
+--
+Use case:
+
+ x
+ x/y
+
+If x/y is empty, and x processed first, the x will
+not be removed.
+
+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,
+
+ x/y
+ x
+
+While at it, update an example of New to give preview of input and
+what the expected output for certain operations.
+--
+
+* lib/xmlrpc: rewrite the Client connection using lib/http
++
+--
+Using socket connection require reading the HTTP response header before
+we can process the response body.
+
+Instead of rewrite the parser, use the lib/http to send and receive
+the request/response.
+--
+
+* lib/io: do not use absolute path on dummy Watcher parent SysPath
++
+Converting that parameter path to absolute path may cause unpredictable
+result on module that use it.
+
+[#v0_31_0_chores]
+=== Chores
+
+* lib/ini: add example of marshal/unmarshaling of section with sub
++
+This changes also fix the example of field tag on marshaling the
+map.
+
+* lib/io: add method String to FileState type
++
+The String method return the string representation of FileState.
+Usually used only for debugging.
+
+* lib/memfs: remove unnecessary initialization on NewNode
++
+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.
+
+* lib/io: use t.Cleanup instead of defer on test
+
+
+[#v0_30_0]
+== share v0.30.0 (2021-10-04)
+
+[#v0_30_0_breaking_changes]
+=== Breaking changes
+
+* lib/io: separate FileState for updated mode and content
++
+--
+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.
+
+This changes separated those state into two kind: FileStateUpdateMode
+for update on file mode, and FileStateUpdateContent for update on
+file content.
+--
+
+[#v0_30_0_new_features]
+=== New features
+
+* lib/memfs: export the Node Update method
++
+--
+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.
+
+The newInfo parameter is optional, if its nil, it will read the file
+information based on node's SysPath.
+
+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.
+
+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.
+--
+
+* lib/strings: add function Alnum
++
+--
+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.
+--
+
+[#v0_30_0_bug_fixes]
+=== Bug fixes
+
+* lib/memfs: fix symlink to directory not included on mount
++
+--
+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.
+
+The fix is to check if node mode is symlink first and then get the
+the real stat.
+--
+
+* lib/io: fix NewWatcher when called DirWatcher
++
+--
+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.
+
+Any operation using new node SysPath will failed because the path
+does not exist or reachable from current directory.
+
+For example, let say we have the following directory tree,
+
+ testdata
+ |
+ +--- A
+ |
+ +--- B
+
+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".
+
+Later, when node content need to be read, ioutil.ReadFile("A") will
+fail because the path to "A" does not exist on current directory.
+
+This fix require to force the parameter "parent" on NewNode to be
+required.
+--
+
+* lib/memfs: fix possible data race on PathNode
++
+--
+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()
+
+At the same time, there maybe a request to access another path, which
+cause both read and write occured.
+--
+
+* lib/memfs: fix NewNode if node is symlink to directory
++
+--
+Previously, if a symlink point to directory the memfs NewNode function
+will return an error,
+
+ AddChild wui: NewNode: read x/y: is a directory
+
+which cause the files inside y cannot be scanned (404).
+
+This commit fix this issue by checking if the original node mode is a
+directory and return immediately.
+--
+
+[#v0_30_0_enhancements]
+=== Enhancements
+
+* lib/memfs: check error on File Close on GoGenerate
++
+--
+Previously, we ignore the error for call to Close when there is an
+error in previous operation.
+
+This changes check the error returned from Close and add it to the
+returned error message.
+
+While at it, use consisten prefix for all returned error:
+"MemFS.GoGenerate".
+--
+
+* lib/http: support server caching file system using ETag
++
+--
+If the Server handle file system using MemFS, server will set the
+ETag [1] header using the file epoch as value.
+
+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.
+
+[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
+--
+
+* lib/xmlrpc: convert the value using Sprintf on GetFieldAsString
++
+--
+Previously, the GetFieldAsString will return empty string if the
+Value type is not string.
+
+In this commit, we force the value to be string by converted it using
+fmt.Sprintf.
+--
+
+* math/big: add some examples of Rat.Int64() and RoundToNearestAway
+
+[#v0_30_0_chores]
+=== Chores
+
+* github: update the Go version to v1.17.1
+
+* lib/strings: update comment and example of TrimAlnum
+
+
+[#v0_29_2]
+== share v0.29.2 (2021-09-06)
+
+[#v0_29_2_bug_fixes]
+=== Bug fixes
+
+* os/exec: fix escaped quote inside the same quote
++
+--
+Shell quote is a hell of complex. For example, one can write
+shell that execute command that contains quote of quote,
+
+ sh -c "psql -c 'CREATE ... IDENTIFIED BY PASSWORD '\''pass'\'''"
+
+or to simplify,
+
+ sh -c "psql -c \"CREATE ... IDENTIFIED BY PASSWORD 'pass'\""
+--
+
+* lib/memfs: fix empty ContentType if MaxFileSize is negative
++
+A negative MaxFileSize means the content of file will not be mapped to
+memory, but the content type should be detected for other operation.
+
+* lib/memfs: fix empty file not being added to tree
++
+--
+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.
+
+This commit fix this issue by checking for zero file size and for
+io.EOF when reading the file content.
+--
+
+* lib/memfs: fix symbolic link with different name
++
+--
+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
+
+ parentpath/filename: no such file or directory
+
+because we use the original file name, not the symlinked file name.
+
+This commit fix this issue by not replacing the original FileInfo for
+symlink but by setting only the size and mode.
+--
+
+* lib/sql: do not run migration if the last file not exist on the list
++
+--
+Previously, if the last migrated file name not found on the migration
+directory, we start executing migration start from the first file.
+
+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.
+--
+
+* lib/http: fix missing content type for XML Header
++
+If the Endpoint set the RequestType to RequestTypeXML, the response
+header should be set to ContentTypeXML.
+
+* lib/xmlrpc: fix missing port on NewClient
++
+--
+Calling net.Dial or tls.Dial on host without port will cause the
+following error,
+
+ NewClient: Dial: dial tcp: address 10.148.0.164: missing port in address
+
+This changes fix this by always generate new host value using previous
+host and port values.
+--
+
+* lib/smtp: return io.EOF if no data received from server
++
+This is to prevent the recv return nil on *Response without an error,
+which may cause panic on caller side.
+
+* os/exec: check for escaped backslash when ParseCommandArgs
++
+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.
+
+[#v0_29_2_enhancements]
+=== Enhancements
+
+* lib/memfs: set default content type for empty file to "text/plain"
++
+An empty file should be able to be displayed as text file instead of
+downloaded as binary.
+
+* lib/memfs: change the MarshalJSON to always return an object
++
+--
+Previously, MarshalJSON on memfs will return an object of map
+of all PathNodes and on Node it will return an object.
+
+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.
+
+While at it, use single "mod_time" with value is epoch and return
+the node ContentType as "content_type".
+--
+
+* lib/mlog: implement io.Writer and add function ErrorWriter
++
+--
+The ErrorWriter will return the internal default MultiLogger.
+A call to Write() on returned io.Writer will forward it to all registered
+error writers.
+
+A Write method on MultiLogger write the b to all error writers.
+It will always return the length of b without an error.
+--
+
+* lib/memfs: add method Save and Encode
++
+The Save method will write the new content to file system and update
+the content of Node using Encode().
+
+* lib/ssh: add method to set session output and error
++
+--
+Previously, all of the SSH output and error goes to os.Stdout and
+os.Stderr.
+
+This changes add method SetSessionOutputError to change the output and
+error for future remote execution.
+--
+
+[#v0_29_2_chores]
+=== Chores
+
+* lib/reflect: make the IsNil tests to become an example
++
+--
+In this way we do test and provide an example at the same time.
+
+While at it, add another test cases for boolean, initialized slice, map,
+and errors.
+--
+
+* lib/websocket: try to fix flaky test on client
++
+--
+The following error thrown when running on Github Action using
+Ubuntu-latest and Go 1.16.3,
+
+ client_test.go:472: write tcp 127.0.0.1:34460->127.0.0.1:9001:
+ write: connection reset by peer
+
+This may be caused by using the same client connection on all test
+cases.
+
+We try to fix this by creating new client on each test cases.
+--
+
+
+[#v0_29_1]
+== share v0.29.1 (2021-08-06)
+
+Revert the "lib/errors: return the internal error only if its not nil on
+Unwrap".
+
+Returning instance of e on Unwrap will cause recursive call.
+
+The correct solution to convert an error to errors.E is by implementing the As
+method.
+
+
+[#v0_29_0]
+== share v0.29.0 (2021-08-06)
+
+[#v0_29_0_new_feature]
+=== New feature
+
+ssh/sftp: new package that implement SSH File Transport Protocol v3
+
+The sftp package extend the golang.org/x/crypto/ssh package by
+implementing "sftp" subsystem using the ssh.Client connection.
+
+[#v0_29_0_breaking_changes]
+=== Breaking changes
+
+* text/diff: add functions to compare raw bytes as text and text.Lines
++
+--
+This changes refactoring some functions, notably,
+
+* Rename Bytes function to IsEqual
+* Rename Lines function to Bytes
+* Add function Text that compare two text (raw bytes)
+* Add function Lines that compare two instances of text.Lines
+--
+
+[#v0_29_0_enhancements]
+=== Enhancements
+
+* lib/mlog: add function and method Panicf
++
+The Panicf method is equal to Errf followed by panic. This signature
+follow the log.Panicf convention.
+
+* lib/text: implement function to parse raw bytes into Lines
+
+* lib/text: implement Stringer on Chunk and Line types
+
+* lib/memfs: implement json.Marshaler on MemFS and Node
++
+--
+Previously, without MarshalJSON, encoding the MemFS or Node object will
+result in incomplete information, for example, missing name, modification
+time, and size.
+
+This commit implement the json.Marshaler in MemFS which encode the
+PathNode sorted by keys in ascending order.
+--
+
+* lib/bytes: print the ASCII character on the right side on PrintHex
++
+--
+Previously, PrintHex only print the hex value of all bytes with
+specified length.
+
+This changes also print any printables ASCII characters (char 33 through
+126) in the right side column to view readable contents.
+--
+
+* lib/totp: lib/totp: increase the maximum steps back on Verify from 2 to 20
++
+The value 20 means the Verify will check maximum 20 TOTP tokens or 10
+minutes to the past.
+
+* lib/http: check request path as HTML file on getFSNode
++
+--
+Previously, if the request path is not exist we check if request
+contains index.html and if still not exist we return nil.
+
+This commit add another check by appending ".html" to the request path.
+
+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".
+--
+
+[#v0_29_0_bug_fixes]
+=== Bug fix
+
+* lib/errors: return the internal error only if its not nil on Unwrap
++
+If the internal error is nil, the Unwrap method will return the instance
+of e itself.
+
+
+[#v0_28_0]
+== share v0.28.0 (2021-07-06)
+
+[#v0_28_0_breaking_changes]
+=== Breaking changes
+
+* lib/ssh: rename method Get to ScpGet and Put to ScpPut
++
+--
+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.
+
+While at it, use consistent log prefix for error message.
+--
+
+* ssh: rename the NewClient function to NewClientFromConfig
++
+This is to differentiate it with x/crypto ssh package that have the same
+function name.
+
+* ssh: move the config parser to subpackage "config"
++
+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.
+
+* http: remove the Memfs field from Server
++
+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.
+
+[#v0_28_0_enhancements]
+=== Enhancements
+
+* websocket: export the Options field on the Server
++
+--
+Previously, the Options field is not exported to prevent user from
+changing it once it set through NewServer() function.
+
+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.
+--
+
+* http: export the Options field on the Server
++
+--
+Previously, the Options field is not exported to prevent user from
+changing it once it set through NewServer() function.
+
+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.
+--
+
+* websocket: store all the handshake headers to Handshake.Header
++
+--
+Previously only non-required headers are stored in the Handshake Header
+field, while the required header value stored on their respective fields.
+
+This commit store all request header key and values into the Header field.
+--
+
+[#v0_27_0]
+== share v0.27.0 (2021-06-05)
+
+This release bring better functionalities, usability, and fixes for `xmlrpc`
+package.
+
+[#v0_27_0_breaking_changes]
+=== Breaking changes
+
+* xmlrpc: change the Response to embed the errors.E
++
+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.
+
+* xmlrpc: write the XML header when marshaling request not on client
++
+--
+Previously, the XML header is added when sending the request using
+client.
+
+This commit changes it to write the header when marshaling the Request
+instance.
+--
+
+* xmlrpc: replace Value field for struct with map of string and value
++
+--
+Previously, for param with type "struct" is represented by slice of
+Member{Name,Value}.
+
+This commit changes the Value field for "struct" to a map of string and
+value for easily access the struct's member, without looping.
+--
+
+* xmlrpc: refactoring the parser for decoding XML-RPC request
++
+--
+This changes,
+
+* method to parse XML-RPC request,
+* change the Member field Value type to pointer to Value,
+* change the Request field Params type to slice of pointer of Value,
+* change the Response field Param type to pointer to Value,
+* rename the Value fields from Members to StructMembers and Values to
+ ArrayValues
+--
+
+[#v0_27_0_new_features]
+=== New features
+
+* memfs: add function to Merge one or more instance of MemFS
++
+--
+The Merge function merge one or more instance of MemFS into single MemFS
+instance.
+
+If there are two instance of Node that have the same path, the last
+instance will be ignored.
+--
+
+* xmlrpc: add method to marshal Response
+
+* mlog: add function and method PrintStack
++
+The PrintStack function or method will writes to error writers the stack
+trace returned by debug.Stack.
+
+[#v0_27_0_enhancements]
+=== Enhancements
+
+* http: add request type for XML
++
+Setting Endpoint's RequestType to RequestTypeXML will check the content
+type of HTTP request to match with "text/xml".
+
+[#v0_27_0_bug_fixes]
+=== Bug fixes
+
+* memfs: set the field Parent on Node AddChild
+
+* xmlrpc: convert the uint8 and uint16 as type Integer, and Uint as Double
++
+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.
+
+* xmlrpc: set client response IsFault when StatusCode >= 400
++
+Previously, we set IsFault to true if the HTTP response code not equal to
+200 only, which is not always correct.
++
+This commit changes it to check any status code that is greater or equal
+to 400.
+
+* memfs: fix test by checking multiple content-types
++
+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".
+
+
+[#v0_26_0]
+== share v0.26.0 (2021-05-03)
+
+[#v0_26_0_new_features]
+=== New features
+
+* math/big: add method Add, IsLess, IsGreater, and Scan on Int
++
+The Add method simplify addition of one value to current Int.
++
+The IsLess and IsGreater method simplify comparing Int with any value.
++
+The Scan method allow the Int to be used on sql Scan().
+
+* math/big: add method IsZero on Int
++
+The IsZero method will return true if the current i value is zero.
+
+* big: extends the standard big.Int
++
+The standard big.Int does not implement sql/driver.Valuer interface,
+which make it not usable when querying or doing update/insert with
+database.
++
+This commit extend the big.Int and simplify creating new Int from any
+values using NewInt().
++
+Also, make it support marshal/unmarshal JSON
+
+[#v0_26_0_enhancements]
+=== Enhancements
+
+* sql: make the column filename on table _migration as primary key
++
+This will allow deleting the record by filename instead of requiring
+all columns.
+
+* http: add the Total field to EndpointResponse
++
+The Total field contains the total number of all records, while the
+Count fields only contains the total number of records in Data.
+
+* http: add field Page to EndpointResponse
++
+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.
++
+While at it, move the field comment to its declaration.
+
+* big: allow creating new Rat from uint64 and *big.Int
+
+* ssh: check for empty private key file on Get and Put
++
+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.
+
+[#v0_26_0_chores]
+=== Chores
+
+* memfs: update the test ContentType for JavaScript files
++
+The latest Go set the content type for JavaScript file as
+"text/javascript; charset=utf-8", not "application/javascript".
+
+* paseto: replace le64() function with binary.Write()
++
+The le64() return the string representation of uint64 in little endian,
+which is basically binary.Write with parameter output buffer,
+LittleEndian, and input value.
+
+
+[#v0_25_1]
+== share v0.25.1 (2021-04-06)
+
+Set the minimum Go version to 1.16
+
+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.
+
+We choose to move forward.
+
+
+[#v0_25_0]
+== share v0.25.0 (2021-04-06)
+
+[#v0_25_0_breaking_changes]
+=== Breaking changes
+
+* all: refactoring the test.Assert and test.AssertBench signature
++
+Previously, the test.Assert and test.AssertBench functions has the
+boolean parameter to print the stack trace of test in case its not equal.
++
+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.
+
+* all: refactoring http.Client methods signature
++
+--
+Previously, parameters to method Delete, Get, Post, PostForm, PostFormData,
+PostJSON, Put, and PutJSON are in the following order:
+
+ (headers, path, params)
+
+This is sometimes confusing. To make it better and works with format
+of HTTP request header,
+
+----
+METHOD PATH
+HEADERS
+
+PARAMS
+----
+
+we move the path to the first parameter and headers as the second
+parameter, so the call to client methods would be
+
+ (path, headers, params)
+--
+
+* http: remove parameter contentType on Client method Put
++
+Since one can set the Content-Type in parameter headers, this parameter is
+become redundant.
+
+[#v0_25_0_new_features]
+=== New features
+
+* http: add method to generate standard HTTP request on Client
++
+--
+The GenerateHttpRequest method generate http.Request instance from
+method, path, requestType, headers, and params.
+
+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.
+
+For HTTP method is PATCH, POST, or PUT; the params will converted based on
+requestType rules below,
+
+* If requestType is RequestTypeQuery and params is url.Values it will be
+ added as query parameters in the path.
+
+* If requestType is RequestTypeForm and params is url.Values it will be
+ added as URL encoded in the body.
+
+* If requestType is RequestTypeMultipartForm and params type is
+ map[string][]byte, then it will be converted as multipart form in the
+ body.
+
+* If requestType is RequestTypeJSON and params is not nil, the params will
+ be encoded as JSON in body.
+--
+
+* ssh: ask for passphrase if private key is encrypted on generateSigners
++
+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().
++
+This changes also remove call to generateSigners on postConfig(),
+instead invoke it from NewClient() to minimize multiple calls to
+generateSigners().
+
+* ssh: use the SSH agent to authenticate on NewClient
++
+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.
++
+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.
++
+This method need manual key added by user to SSH agent before calling
+NewClient to make it works.
+
+[#v0_25_0_enhancements]
+=== Enhancements
+
+* xmlrpc: add debug statements to print request and response
++
+The debug level is set minimum to 3. If its set it will print the
+request and response to standard output.
+
+
+[#v0_24_0]
+== share v0.24.0 (2021-03-06)
+
+[#v0_24_0_breaking_changes]
+=== Breaking changes
+
+* http: add prefix Header to constants AcceptEncoding and ContentEncoding
++
+Since both of those constants are used only for HTTP header, it could
+be more clear if we prefix it with "Header".
+
+* sql: change the parameter ExtractSQLFields to driver name
++
+Previously, we use the string as parameter to set the returned place
+holders.
++
+This commit changes the parameter to the driver name so if the value
+is "postgres" the place holders will be returned as counter, for example
+"$1", "$2", and so on.
+
+* http: rename "GenericResponse" to "EndpointResponse"
++
+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.
+
+* http: refactoring parameters on Callback and CallbackErrorHandler
++
+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.
++
+This changes wrap the three parameters into single type EndpointRequest
+with addition field Endpoint, which contains the registered Endpoint.
++
+On the CallbackErrorHandler we also have three parameters, but instead
+of request body we have an error.
++
+This changes store the error for CallbackErrorHandler inside
+EndpointRequest.Error field.
+
+* http: move the CORS options to separate struct
+
+[#v0_24_0_new_features]
+=== New features
+
+* http: add methods IPAddressOfRequest and ParseXForwardedFor
++
+The IPAddressOfRequest get the client IP address from HTTP request header
+"X-Real-IP" or "X-Forwarded-For" or from Request.RemoteAddr, which ever
+non-empty first.
++
+The ParseXForwardedFor parse the HTTP header "X-Forwarded-For" value from
+the following format "client, proxy1, proxy2" into client address and
+list of proxy addressess.
+
+* api/slack: create new client for webhook
++
+Unlike PostWebhook API which is close and open one connection at the
+time, the WebhookClient is keep open.
++
+Use the WebhookClient for long running program that post message every
+minutes or seconds.
+
+* mlog: implement MultiLogger
++
+--
+MultiLogger represent a single log writer that write to multiple outputs.
+MultiLogger can have zero or more writers for standard output (normal log)
+and zero or more writers for standard error.
+
+The MultiLogger is buffered to minimize waiting time when writing to
+multiple writers that have different latencies.
+For example, if we have one writer to os.Stdout, one writer to file, and
+one writer to network; the writer to network may take more time to finish
+than to os.Stdout and file, which may slowing down the program if we want
+to wait for all writes to finish.
+
+For this reason, do not forget to call Flush when your program exit.
+
+The default MultiLogger use time.RFC3339 as the default time layout, empty
+prefix, os.Stdout for the output writer, and os.Stderr for the error
+writer.
+
+Format of written log,
+
+ [time] [prefix] <message>
+
+The time and prefix only printed if its not empty, and the single space is
+added for convenience.
+Unlike standard log package, this package does not add new line to the end
+of message if its not exist.
+--
+
+* http: export the HandleFS method
++
+The HandleFS handle the request as resource in the memory file system.
+This method only works if the Server.Memfs is not nil.
++
+If the request Path exists in file system, it will return 200 OK with the
+header Content-Type set accordingly to the detected file type and the
+response body set to the content of file.
+If the request Method is HEAD, only the header will be sent back to client.
++
+If the request Path is not exist it will return 404 Not Found.
+
+* clise: add method Pop
++
+The Pop method remove the last Push()-ed item and return it to caller.
+It will return nil if no more item inside it.
+
+* ini: add support for marshaling slice of struct
++
+--
+Given a struct with exported field is slice of struct and tagged with
+section and sub-section, the exported field will be marshalled as,
+
+ [section "sub"]
+ field = value
+--
+
+* ini: add support for marshaling pointer to struct and to time.Time
++
+--
+Given the following field struct with tag,
+
+ V *T `ini:"sec:sub"
+
+If the V is not nil, it will marshal it into,
+
+ [sec "sub"]
+ <field name or tag> = <field value>
+--
+
+* ini: add support for un-marshaling to struct and slice of struct
+
+* big: add method that implement sql/driver.Valuer for type Rat
++
+The Rat.Value() return the value as []byte.
+
+[#v0_24_0_enhancements]
+=== Enhancements
+
+* clise: make all methods safe for concurrent use
+
+* http: add fields for paging on GenericResponse
++
+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.
++
+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.
+
+[#v0_24_0_bug_fixes]
+=== Bug fixes
+
+* reflect: check using equal statement on IsNil
++
+Beside using IsNil(), return the last check using "v == nil".
+
+
+[#v0_23_0]
+== share v0.23.0 (2021-02-05)
+
+This release bring major refactoring to package memfs to allow embedding two
+or more directories in single package.
+
+The minimum Go version is increased to 1.14.
+
+[#v0_23_0_breaking_changes]
+=== Breaking changes
+
+* memfs: refactoring, allow multiple instances of memfs in single package
++
+Previously, the generated Go code from memfs can be used only once
+on the package that use it. For example, if we have two instances of
+memfs.MemFS and both of them call GoGenerate(), when we load them back
+again only the last one will be active and set the global variable
+memfs.GeneratedPathNode.
++
+This changes refactoring on how we use memfs by storing the
+generated path node into variable that is defined by user and pass
+them to New Options.
+
+* memfs: remove field WithContent
++
+The field WithContent is not necessary if we set MaxFileSize to negative
+value.
+
+* http: embed the memfs.Options into ServerOptions
++
+This is to minimize duplicate on fields names and give clear distinction
+between options for Server and options for serving files on memory using
+memfs.
+
+* io: embed the memfs.Options into DirWatcher
++
+This is to minimize duplicate configuration between DirWatcher and
+memfs, and to allow clear distinction between which options that
+affect the directory tree and options for DirWatcher.
+
+* memfs: allow AddFile to set internal path
++
+Previously, AddFile set the internal path equal to path of file to be
+included. This may cause conflict if the file is already included
+due to the same sys path but different internal path.
++
+This commit add parameter internalPath to set custom internal path in
+the memfs map.
+
+* memfs: refactoring Go generate code to use memfs.MemFS instance
++
+Instead of using memfs.PathNode, which is confusing for new user
+(what is PathNode?), we actually can use memfs.MemFS instance.
++
+This effect on how we use memfs in http package.
+
+* dns: change the SOA field in ZoneFile to non-pointer
++
+The reason we use pointer for SOA record is so we can save them only
+if its not nil. A nil SOA record cause the generated JSON become "null"
+and this is make the consumer of ZoneFile do more work, checking for the
+null and initialize it when required.
++
+This changes, make the SOA record to non-nil and we save the record only
+if the MName field is not empty.
+
+* dns: replace master word with zone
++
+This is for consistency for type and variable names.
+
+* sql: sort returned names on ExtractSQLFields sorted in ascending
++
+This is to make sure that any test that use the package always
+predictable.
++
+While at it, add paramter to change placeholder on ExtractSQLFields.
+
+[#v0_23_0_new_features]
+=== New features
+
+* http: add method Post on client
++
+The Post method send the POST request to path without setting
+"Content-Type".
+
+* lib/clise: new package that implement circular slice
++
+--
+A circular slice is a slice that have fixed size.
+An append to slice that has reached its length will overwrite and start
+again from index 0.
+
+For example, a clise with size 5,
+
+ c := clise.New(5)
+ c.Push(1, 2, 3, 4, 5)
+ fmt.Printf("%v\n", c.Slice()) // [1 2 3 4 5]
+
+If we push another item, it will overwrite the first index,
+
+ c.Push(6)
+ fmt.Printf("%v\n", c.Slice()) // [6 2 3 4 5]
+
+See the examples for usage of the package.
+--
+
+* time: add function UnixMicro that return UNIX time in micro seconds
+
+* api/slack: simple API for sending message to Slack using only
+ standard packages.
+
+* runes: add function to inverse the slice of rune
++
+The Inverse function reverse the order of slice of rune without
+allocating another slice.
+
+* big: add method Humanize
++
+The Humanize method return the r as string with custom thousand and
+decimal separator.
+
+* big: add method to round fraction to nearest non-zero value
++
+The RoundNearestFraction does not require precision parameter, like in
+other rounds function, but it figure it out based on the last non-zero
+value from fraction.
+
+[#v0_23_0_enhancements]
+=== Enhancements
+
+* dns: change the error messages on ResourceRecord initAndInitialize
++
+This change make the error message more readable and understandable by
+consumer
+
+* dns: add method to get list of non-local caches in the Server
++
+The CachesLRU method return the list of non-local caches ordered by
+the least recently used.
++
+This changes affect the answer type which must be exported, including
+most of its fields, so consumer can access it.
+
+[#v0_23_0_bug_fixes]
+=== Bug fixes
+
+* sql: check nil on Migrate parameter "fs" using reflect.IsNil
++
+If we pass nil pointer of type to fs, the if condition will not true
+and this cause panic because fs is not nil.
+
+* http: fix the package documentation
++
+The RegisterXxx methods on Server has been replaced with single method,
+RegisterEndpoint.
+
+* dns: fix saving the TXT record file on zone file
++
+The TXT record value must be wrapped with quote when stored on zone
+file.
+
+
+[#v0_22_0]
+== share v0.22.0 (2021-01-06)
+
+[#v0_22_0_breaking_changes]
+=== Breaking changes
+
+* contact: remove unused package proofn
+
+* sql: change the new client function parameter into struct of options.
+
+[#v0_22_0_new_features]
+=== New features
+
+* cmd: add new CLI "totp"
++
+The totp is a program to generate Time-based One-time Password from
+secret key.
+
+* totp: add method to generate n number of passwords
+
+[#v0_22_0_enhancements]
+=== Enhancements
+
+* http: print client request if debug value is equal or greater than 2.
++
+If user set DEBUG environment variable or debug.Value to 2 or greater,
+the http Client will print the request (header and body) to the
+standard output.
+
+* ssh: print the private key file that has an error when generating signers
diff --git a/_doc/index.adoc b/_doc/index.adoc
index 3fb290d2..e9c851f6 100644
--- a/_doc/index.adoc
+++ b/_doc/index.adoc
@@ -1,5 +1,6 @@
# shuLhan/share internal documentation
Shulhan <ms@kilabit.info>
+:toc:
Beside
https://pkg.go.dev/github.com/shuLhan/share#section-documentation[the Go documentation],
@@ -10,7 +11,35 @@ their scope and limitation of Go doc formatting itself.
NOTE: The links below is used to be viewed locally, not through Github or
pkg.go.dev.
-* link:CHANGELOG.html[CHANGELOG]
+The documentation is created and generated using
+https://git.sr.ht/~shulhan/ciigo[`ciigo`].
+
+To serve documentation on HTTP server at http://127.0.0.1:21019 and watch
+changes on documentation files (".adoc") and regenerate the HTML
+files, run
+
+----
+$ make docs-serve
+----
+
+
+== Changelog
+
+This library is released every month, usually at the first week of month.
+
+link:CHANGELOG.html[Latest changelog^].
+
+link:CHANGELOG_2021.html[Changelog in 2021^].
+This is changelog for share module since v0.22.0 until v0.32.0.
+
+link:CHANGELOG_2020.html[Changelog in 2020^].
+This is changelog for share module since v0.12.0 until v0.21.0.
+
+link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^].
+This is changelog for share v0.1.0 until v0.11.0.
+
+
+== Simplified RFCs
* link:IMF.html[Internet Message Format (RFC 5322)]
** link:MIME_I_FORMAT.html[MIME Part One: Format of Internet Message Bodies (RFC 2045)]
@@ -32,21 +61,4 @@ pkg.go.dev.
* link:SPF.html[Sender Policy Framework version 1 (RFC 7208)]
-The documentation is created and generated using
-https://git.sr.ht/~shulhan/ciigo[`ciigo`].
-
-To serve documentation on HTTP server at http://127.0.0.1:21019 and watch
-changes on documentation files (".adoc") and regenerate the HTML
-files, run
-
-----
-$ make docs-serve
-----
-
-To generate HTML files for all asciidoc files, run
-
-----
-$ make docs
-----
-
That's it! Happy hacking!
diff --git a/_doc/index.html b/_doc/index.html
index 814c154b..28117791 100644
--- a/_doc/index.html
+++ b/_doc/index.html
@@ -187,6 +187,14 @@ dd {
margin: 2.5rem 0;
}
+.ulist li .paragraph {
+ margin-bottom: 1em;
+}
+
+.ulist li .paragraph {
+ margin-bottom: 1em;
+}
+
/** Custom classes */
#toctitle {
display: none;
@@ -233,6 +241,14 @@ dd {
<span id="author" class="author">Shulhan</span><br>
<span id="email" class="email"><a href="mailto:ms@kilabit.info">ms@kilabit.info</a></span><br>
</div>
+<div id="toc" class="toc">
+<div id="toctitle">Table of Contents</div>
+<ul class="sectlevel1">
+<li><a href="#_changelog">Changelog</a></li>
+<li><a href="#_simplified_rfcs">Simplified RFCs</a></li>
+</ul>
+
+</div>
</div>
<div id="content">
<div id="preamble">
@@ -257,13 +273,51 @@ pkg.go.dev.
</tr>
</table>
</div>
+<div class="paragraph">
+<p>The documentation is created and generated using
+<a href="https://git.sr.ht/~shulhan/ciigo"><code>ciigo</code></a>.</p>
+</div>
+<div class="paragraph">
+<p>To serve documentation on HTTP server at <a href="http://127.0.0.1:21019" class="bare">http://127.0.0.1:21019</a> and watch
+changes on documentation files (".adoc") and regenerate the HTML
+files, run</p>
+</div>
+<div class="listingblock">
+<div class="content">
+<pre>$ make docs-serve</pre>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_changelog">Changelog</h2>
+<div class="sectionbody">
+<div class="paragraph">
+<p>This library is released every month, usually at the first week of month.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG.html" target="_blank" rel="noopener">Latest changelog</a>.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2021.html" target="_blank" rel="noopener">Changelog in 2021</a>.
+This is changelog for share module since v0.22.0 until v0.32.0.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2020.html" target="_blank" rel="noopener">Changelog in 2020</a>.
+This is changelog for share module since v0.12.0 until v0.21.0.</p>
+</div>
+<div class="paragraph">
+<p><a href="CHANGELOG_2018-2019.html" target="_blank" rel="noopener">Changelog from 2018 to 2019</a>.
+This is changelog for share v0.1.0 until v0.11.0.</p>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_simplified_rfcs">Simplified RFCs</h2>
+<div class="sectionbody">
<div class="ulist">
<ul>
<li>
-<p><a href="CHANGELOG.html">CHANGELOG</a>
-</p>
-</li>
-<li>
<p><a href="IMF.html">Internet Message Format (RFC 5322)</a>
</p>
<div class="ulist">
@@ -342,28 +396,6 @@ pkg.go.dev.
</ul>
</div>
<div class="paragraph">
-<p>The documentation is created and generated using
-<a href="https://git.sr.ht/~shulhan/ciigo"><code>ciigo</code></a>.</p>
-</div>
-<div class="paragraph">
-<p>To serve documentation on HTTP server at <a href="http://127.0.0.1:21019" class="bare">http://127.0.0.1:21019</a> and watch
-changes on documentation files (".adoc") and regenerate the HTML
-files, run</p>
-</div>
-<div class="listingblock">
-<div class="content">
-<pre>$ make docs-serve</pre>
-</div>
-</div>
-<div class="paragraph">
-<p>To generate HTML files for all asciidoc files, run</p>
-</div>
-<div class="listingblock">
-<div class="content">
-<pre>$ make docs</pre>
-</div>
-</div>
-<div class="paragraph">
<p>That&#8217;s it! Happy hacking!</p>
</div>
</div>
@@ -371,7 +403,7 @@ files, run</p>
</div>
<div id="footer">
<div id="footer-text">
-Last updated 2022-02-18 12:30:22 +0700
+Last updated 2022-07-03 14:34:51 +0700
</div>
</div>
</div>