{"id":15446197,"url":"https://github.com/moul/u","last_synced_at":"2025-04-14T09:50:55.371Z","repository":{"id":37102010,"uuid":"284363947","full_name":"moul/u","owner":"moul","description":"🔬 Go common utility functions","archived":false,"fork":false,"pushed_at":"2025-03-24T15:31:36.000Z","size":190,"stargazers_count":8,"open_issues_count":12,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T23:06:39.778Z","etag":null,"topics":["common","golang","helpers","library","standard"],"latest_commit_sha":null,"homepage":"https://manfred.life/golang","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moul.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE-APACHE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["moul"],"patreon":"moul","open_collective":"moul","custom":["https://manfred.life/donate"]}},"created_at":"2020-08-02T00:45:33.000Z","updated_at":"2024-07-27T00:14:41.000Z","dependencies_parsed_at":"2023-02-16T15:46:12.629Z","dependency_job_id":"0a797303-a77e-4477-af2b-7678a7cf4a2b","html_url":"https://github.com/moul/u","commit_stats":{"total_commits":81,"total_committers":6,"mean_commits":13.5,"dds":0.4320987654320988,"last_synced_commit":"0a441d5a7f6abbaae1df674f4ba7249600f41f62"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":"moul/golang-repo-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moul%2Fu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moul","download_url":"https://codeload.github.com/moul/u/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248859499,"owners_count":21173336,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["common","golang","helpers","library","standard"],"created_at":"2024-10-01T19:59:47.278Z","updated_at":"2025-04-14T09:50:55.321Z","avatar_url":"https://github.com/moul.png","language":"Go","funding_links":["https://github.com/sponsors/moul","https://patreon.com/moul","https://opencollective.com/moul","https://manfred.life/donate"],"categories":[],"sub_categories":[],"readme":"# u\n\n:smile:  Go common utility functions\n\n[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go\u0026logoColor=white)](https://pkg.go.dev/moul.io/u)\n[![License](https://img.shields.io/badge/license-Apache--2.0%20%2F%20MIT-%2397ca00.svg)](https://github.com/moul/u/blob/master/COPYRIGHT)\n[![GitHub release](https://img.shields.io/github/release/moul/u.svg)](https://github.com/moul/u/releases)\n[![Made by Manfred Touron](https://img.shields.io/badge/made%20by-Manfred%20Touron-blue.svg?style=flat)](https://manfred.life/)\n\n[![Go](https://github.com/moul/u/workflows/Go/badge.svg)](https://github.com/moul/u/actions?query=workflow%3AGo)\n[![Release](https://github.com/moul/u/workflows/Release/badge.svg)](https://github.com/moul/u/actions?query=workflow%3ARelease)\n[![PR](https://github.com/moul/u/workflows/PR/badge.svg)](https://github.com/moul/u/actions?query=workflow%3APR)\n[![GolangCI](https://golangci.com/badges/github.com/moul/u.svg)](https://golangci.com/r/github.com/moul/u)\n[![codecov](https://codecov.io/gh/moul/u/branch/master/graph/badge.svg)](https://codecov.io/gh/moul/u)\n[![Go Report Card](https://goreportcard.com/badge/moul.io/u)](https://goreportcard.com/report/moul.io/u)\n[![CodeFactor](https://www.codefactor.io/repository/github/moul/u/badge)](https://www.codefactor.io/repository/github/moul/u)\n\nInspired by https://github.com/kjk/u\n\n## Usage\n\n[embedmd]:# (.tmp/godoc.txt txt /FUNCTIONS/ $)\n```txt\nFUNCTIONS\n\nfunc B64Decode(input string) ([]byte, error)\n    B64Decode try to decode an input string and returns bytes if success.\n\nfunc B64Encode(input []byte) string\n    B64Encode returns a base64 encoded string of input bytes.\n\nfunc BoolPtr(val bool) *bool\n    BoolPtr returns a pointer to a bool of value 'val'.\n\nfunc CaptureStderr() (func() string, error)\n    CaptureStderr temporarily pipes os.Stderr into a buffer.\n\nfunc CaptureStdout() (func() string, error)\n    CaptureStdout temporarily pipes os.Stdout into a buffer.\n\nfunc CaptureStdoutAndStderr() (func() string, error)\n    CaptureStdoutAndStderr temporarily pipes os.Stdout and os.Stderr into a\n    buffer.\n\nfunc CheckErr(err error)\n    CheckErr panics if the passed error is not nil.\n\nfunc CombineFuncs(left func(), right ...func()) func()\n    CombineFuncs create a chain of functions. This can be particularly useful\n    for creating cleanup function progressively. It solves the infinite loop you\n    can have when trying to do it manually:\n    https://play.golang.org/p/NQem8UJ500t.\n\nfunc CommandExists(command string) bool\n    CommandExists checks whether a command is available in the $PATH.\n\nfunc CreateEmptyFileWithSize(path string, size uint) error\n    CreateEmptyFileWithSize creates a new file of the desired size, filled with\n    zeros.\n\nfunc CurrentUsername(fallback string) string\n    CurrentUsename returns the current user's username. If username cannot be\n    retrieved, it returns the passed fallback.\n\nfunc DirExists(path string) bool\n    DirExists checks whether a path exists and is a directory.\n\nfunc ExecStandaloneOutputs(cmd *exec.Cmd) ([]byte, []byte, error)\n    ExecStandaloneOutputs runs the command and returns its standard output and\n    standard error.\n\nfunc ExpandPath(path string) (string, error)\n    ExpandPath performs various expansions on a given path.\n\n    - Replaces ~/ with $HOME/. - Returns absolute path. - Expands env vars.\n    TODO: - Follow symlinks.\n\nfunc FanIn(chans ...\u003c-chan interface{}) \u003c-chan interface{}\n    FanIn merges multiple input chans events into one.\n\nfunc FileExists(path string) bool\n    FileExists checks whether a path exists and is a regular file.\n\nfunc Future(fn func() (interface{}, error)) \u003c-chan FutureRet\n    Future starts running the given function in background and return a chan\n    that will return the result of the execution.\n\nfunc IsASCII(buf []byte) bool\n    IsASCII checks whether a buffer only contains ASCII characters.\n\nfunc IsBinary(buf []byte) bool\n    IsBinary returns whether the provided buffer looks like binary or\n    human-readable.\n\n    It is inspired by the implementation made in the Git project.\n    https://github.com/git/git/blob/49f38e2de47a401fc2b0f4cce38e9f07fb63df48/xdiff-interface.c#L188.\n\nfunc JSON(input interface{}) string\n    JSON returns a JSON representation of the passed input.\n\nfunc MustCaptureStderr() func() string\n    MustCaptureStderr wraps CaptureStderr and panics if initialization fails.\n\nfunc MustCaptureStdout() func() string\n    MustCaptureStdout wraps CaptureStdout and panics if initialization fails.\n\nfunc MustCaptureStdoutAndStderr() func() string\n    MustCaptureStdoutAndStderr wraps CaptureStdoutAndStderr and panics if\n    initialization fails.\n\nfunc MustExpandPath(path string) string\n    MustExpandPath wraps ExpandPath and panics if initialization fails.\n\nfunc MustTempFileName(dir, pattern string) string\n    MustTempFileName wraps TempFileName and panics if initialization fails.\n\nfunc MustTempfileWithContent(content []byte) (*os.File, func())\n    MustTempfileWithContent wraps TempfileWithContent and panics if\n    initialization fails.\n\nfunc PathExists(path string) bool\n    PathExists checks whether a path exists or not.\n\nfunc PrettyJSON(input interface{}) string\n    PrettyJSON returns an indented JSON representation of the passed input.\n\nfunc RandomLetters(n int) string\n    RandomLetters returns a string containing 'n' random letters.\n\nfunc SafeExec(cmd *exec.Cmd) string\n    SafeExec runs a command and return a string containing the combined standard\n    output and standard error. If the program fails, the result of `err` is\n    appended to the output.\n\nfunc Sha1(data []byte) []byte\nfunc Sha1Hex(data []byte) string\nfunc ShortDuration(d time.Duration) string\n    ShortDuration returns a short human-friendly representation of a duration.\n    For duration \u003c 100 days, the output length will be \u003c= 7.\n\nfunc SilentClose(closer io.Closer)\n    SilentClose calls an io.Closer.Close() function and ignore potential errors.\n\n    You can use it as `defer SilenceClose(f)`\n\nfunc TempFileName(dir, pattern string) (string, error)\n    TempFileName returns a valid temporary file name (the file is not created).\n\nfunc TempfileWithContent(content []byte) (*os.File, func(), error)\n    TempfileWithContent creates a tempfile with specified content written in it,\n    it also seeks the file pointer so you can read it directly. The second\n    returned parameter is a cleanup function that closes and removes the temp\n    file.\n\nfunc UniqueInterfaces(input []interface{}) []interface{}\n    UniqueInterfaces removes duplicate values from an interface slice.\n\nfunc UniqueInts(input []int) []int\n    UniqueInts removes duplicate values from an int slice.\n\nfunc UniqueStrings(input []string) []string\n    UniqueStrings removes duplicate values from a string slice.\n\nfunc Unzip(src string, dest string) ([]string, error)\n    Unzip decompresses a zip archive, moving all files and folders within the\n    zip file to an output directory. Based on\n    https://golangcode.com/unzip-files-in-go/ (MIT).\n\nfunc UnzipBytes(src []byte, dest string) ([]string, error)\n    UnzipBytes is similar to Unzip but takes a zip archive as bytes instead of\n    looking for a real file.\n\nfunc WaitForCtrlC()\n\nTYPES\n\ntype FutureRet struct {\n\tRet interface{}\n\tErr error\n}\n    FutureRet is a generic struct returned by Future.\n\ntype MutexMap struct {\n\t// Has unexported fields.\n}\n    MutexMap manages a pool of mutexes that can be get by key. MutexMap is\n    thread-safe.\n\nfunc (mm *MutexMap) Lock(key string) func()\n    Lock locks a mutex by key, and returns a callback for unlocking unlock. Lock\n    will automatically create a new mutex for new keys.\n\nfunc (mm *MutexMap) RLock(key string) func()\n    RLock locks a mutex by key for reading, and returns a callback for unlocking\n    unlock. RLock will automatically create a new mutex for new keys.\n\ntype UniqueChild interface {\n\tSetChild(childFn func(context.Context))\n\tCloseChild()\n}\n    UniqueChild is a goroutine manager (parent) that can only have one child at\n    a time. When you call UniqueChild.SetChild(), UniqueChild cancels the\n    previous child context (if any), then run a new child. The child needs to\n    auto-kill itself when its context is done.\n\nfunc NewUniqueChild(ctx context.Context) UniqueChild\n    NewUniqueChild instantiates and returns a UniqueChild manager.\n\n```\n\nSee [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go\u0026logoColor=white)](https://pkg.go.dev/moul.io/u)\n\n## Install\n\n### Using go\n\n```console\n$ go get moul.io/u\n```\n\n## Benchmarks\n\n[embedmd]:# (.tmp/bench.txt txt)\n```txt\nbenchmark                                           iter           time/iter\n---------                                           ----           ---------\nBenchmarkUnzip-8                                    4101     251654.00 ns/op\nBenchmarkUnzipBytes-8                               4842     213715.00 ns/op\nBenchmarkB64Encode/1-8                          30219784         38.44 ns/op\nBenchmarkB64Encode/1-parallel-8                120309013         10.42 ns/op\nBenchmarkB64Encode/1000-8                         962917       1256.00 ns/op\nBenchmarkB64Encode/1000-parallel-8               1627962        815.00 ns/op\nBenchmarkB64Encode/1000000-8                        1094    1092692.00 ns/op\nBenchmarkB64Encode/1000000-parallel-8               3328     364672.00 ns/op\nBenchmarkB64Decode/1000-8                        1000000       1091.00 ns/op\nBenchmarkB64Decode/1000-parallel-8               1971834        598.80 ns/op\nBenchmarkB64Decode/10000-8                        131664       8624.00 ns/op\nBenchmarkB64Decode/10000-parallel-8               274162       4768.00 ns/op\nBenchmarkB64Decode/100000-8                        15345      77537.00 ns/op\nBenchmarkB64Decode/100000-parallel-8               32480      34873.00 ns/op\nBenchmarkIsBinary/small-valid-8                173952991          6.74 ns/op\nBenchmarkIsBinary/small-valid-parallel-8       836416648          1.45 ns/op\nBenchmarkIsBinary/long-valid-8                   1916740        625.70 ns/op\nBenchmarkIsBinary/long-valid-parallel-8          8315928        149.70 ns/op\nBenchmarkIsBinary/small-invalid-8              170598688          7.08 ns/op\nBenchmarkIsBinary/small-invalid-parallel-8     783116866          1.72 ns/op\nBenchmarkCommandExists/go-8                       145177       8699.00 ns/op\nBenchmarkCommandExists/go-parallel-8              278449       4384.00 ns/op\nBenchmarkCommandExists/asddsa-8                    38422      32856.00 ns/op\nBenchmarkCommandExists/asddsa-parallel-8           69381      18171.00 ns/op\nBenchmarkSafeExec-8                                   92   11439103.00 ns/op\nBenchmarkIsASCII-8                             227565444          5.34 ns/op\nBenchmarkCombineFuncs-8                         23210830         52.56 ns/op\nBenchmarkFuture-8                                4820587        263.70 ns/op\nBenchmarkRandomLetters/1000-8                     783525       1572.00 ns/op\nBenchmarkRandomLetters/1000-parallel-8             91543      12743.00 ns/op\nBenchmarkRandomLetters/10000-8                     81429      14677.00 ns/op\nBenchmarkRandomLetters/10000-parallel-8             9618     127306.00 ns/op\nBenchmarkRandomLetters/100000-8                     8164     148755.00 ns/op\nBenchmarkRandomLetters/100000-parallel-8             914    1299007.00 ns/op\nBenchmarkUniqueStrings/slice1-8                  2245912        553.70 ns/op\nBenchmarkUniqueStrings/slice1-parallel-8         5644569        357.00 ns/op\nBenchmarkUniqueStrings/slice2-8                     9151     114607.00 ns/op\nBenchmarkUniqueStrings/slice2-parallel-8           20236      55601.00 ns/op\nBenchmarkUniqueInts/slice1-8                     3188648        371.30 ns/op\nBenchmarkUniqueInts/slice1-parallel-8            9704232        117.50 ns/op\nBenchmarkUniqueInts/slice2-8                       16548      66907.00 ns/op\nBenchmarkUniqueInts/slice2-parallel-8              57608      21750.00 ns/op\nBenchmarkUniqueInterfaces/slice1-8               1480366        962.20 ns/op\nBenchmarkUniqueInterfaces/slice1-parallel-8      4402994        261.30 ns/op\nBenchmarkUniqueInterfaces/slice2-8                  4614     254938.00 ns/op\nBenchmarkUniqueInterfaces/slice2-parallel-8        10000     125025.00 ns/op\nBenchmarkShortDuration/Simple-8                 23745075         47.64 ns/op\nBenchmarkShortDuration/Simple-parallel-8       100000000         11.24 ns/op\nBenchmarkShortDuration/Complex-8                 4912780        231.40 ns/op\nBenchmarkShortDuration/Complex-parallel-8       13411066         75.40 ns/op\nBenchmarkBoolPtr/serial-8                     1000000000          0.32 ns/op\nBenchmarkBoolPtr/parallel-8                   1000000000          0.28 ns/op\nbenchmark                                           iter          time/iter\n---------                                           ----          ---------\nBenchmarkUnzip-12                                   4551    264133.00 ns/op\nBenchmarkUnzipBytes-12                              4507    243344.00 ns/op\nBenchmarkB64Encode/1-12                         16033570        80.95 ns/op\nBenchmarkB64Encode/1-parallel-12                59893237        17.48 ns/op\nBenchmarkB64Encode/1000-12                        379872      4646.00 ns/op\nBenchmarkB64Encode/1000-parallel-12              1243312       945.10 ns/op\nBenchmarkB64Encode/1000000-12                        315   4063088.00 ns/op\nBenchmarkB64Encode/1000000-parallel-12              2054    597679.00 ns/op\nBenchmarkB64Decode/1000-12                        424038      3637.00 ns/op\nBenchmarkB64Decode/1000-parallel-12              1633958       732.70 ns/op\nBenchmarkB64Decode/10000-12                        33224     35140.00 ns/op\nBenchmarkB64Decode/10000-parallel-12              200544      6350.00 ns/op\nBenchmarkB64Decode/100000-12                        4921    326188.00 ns/op\nBenchmarkB64Decode/100000-parallel-12              24049     49786.00 ns/op\nBenchmarkIsBinary/small-valid-12               123109468         9.29 ns/op\nBenchmarkIsBinary/small-valid-parallel-12      747959686         1.54 ns/op\nBenchmarkIsBinary/long-valid-12                  5283378       240.30 ns/op\nBenchmarkIsBinary/long-valid-parallel-12        26021748        41.87 ns/op\nBenchmarkIsBinary/small-invalid-12             130593402         9.19 ns/op\nBenchmarkIsBinary/small-invalid-parallel-12    662583970         1.57 ns/op\nBenchmarkCommandExists/go-12                      132699      9937.00 ns/op\nBenchmarkCommandExists/go-parallel-12             593409      1715.00 ns/op\nBenchmarkCommandExists/asddsa-12                   24820     52140.00 ns/op\nBenchmarkCommandExists/asddsa-parallel-12         130977      8541.00 ns/op\nBenchmarkSafeExec-12                                 644   2378627.00 ns/op\nBenchmarkCombineFuncs-12                         6741579       204.20 ns/op\nBenchmarkFuture-12                               1504198       780.20 ns/op\nBenchmarkRandomLetters/1000-12                    286212      4019.00 ns/op\nBenchmarkRandomLetters/1000-parallel-12            40786     29071.00 ns/op\nBenchmarkRandomLetters/10000-12                    29296     40241.00 ns/op\nBenchmarkRandomLetters/10000-parallel-12            4363    286588.00 ns/op\nBenchmarkRandomLetters/100000-12                    3165    400320.00 ns/op\nBenchmarkRandomLetters/100000-parallel-12            421   2877871.00 ns/op\nBenchmarkUniqueStrings/slice1-12                  963402      1430.00 ns/op\nBenchmarkUniqueStrings/slice1-parallel-12        4290940       307.50 ns/op\nBenchmarkUniqueStrings/slice2-12                    6712    246924.00 ns/op\nBenchmarkUniqueStrings/slice2-parallel-12          21454     56186.00 ns/op\nBenchmarkUniqueInts/slice1-12                    1453717       834.20 ns/op\nBenchmarkUniqueInts/slice1-parallel-12           7538754       144.30 ns/op\nBenchmarkUniqueInts/slice2-12                      10000    146356.00 ns/op\nBenchmarkUniqueInts/slice2-parallel-12             61899     20556.00 ns/op\nBenchmarkUniqueInterfaces/slice1-12               911822      1778.00 ns/op\nBenchmarkUniqueInterfaces/slice1-parallel-12     3223353       360.10 ns/op\nBenchmarkUniqueInterfaces/slice2-12                 2418    564324.00 ns/op\nBenchmarkUniqueInterfaces/slice2-parallel-12        7670    140357.00 ns/op\nBenchmarkShortDuration/Simple-12                13385139        98.24 ns/op\nBenchmarkShortDuration/Simple-parallel-12       59156300        18.38 ns/op\nBenchmarkShortDuration/Complex-12                2444396       486.20 ns/op\nBenchmarkShortDuration/Complex-parallel-12       9201567       132.90 ns/op\n```\n\n## Contribute\n\n![Contribute \u003c3](https://raw.githubusercontent.com/moul/moul/master/contribute.gif)\n\nI really welcome contributions. Your input is the most precious material. I'm well aware of that and I thank you in advance. Everyone is encouraged to look at what they can do on their own scale; no effort is too small.\n\nEverything on contribution is sum up here: [CONTRIBUTING.md](./CONTRIBUTING.md)\n\n### Contributors ✨\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg)](#contributors)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"http://manfred.life\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/94029?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eManfred Touron\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#maintenance-moul\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"https://github.com/moul/u/commits?author=moul\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/moul/u/commits?author=moul\" title=\"Tests\"\u003e⚠️\u003c/a\u003e \u003ca href=\"https://github.com/moul/u/commits?author=moul\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://manfred.life/moul-bot\"\u003e\u003cimg src=\"https://avatars1.githubusercontent.com/u/41326314?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003emoul-bot\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#maintenance-moul-bot\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://darkodjalevski.me/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/9572827?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDarko Djalevski\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/moul/u/commits?author=Dzalevski\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n\u003c!--\n### Stargazers over time\n\n[![Stargazers over time](https://starchart.cc/moul/u.svg)](https://starchart.cc/moul/u)\n--\u003e\n\n## License\n\n© 2020-2021  [Manfred Touron](https://manfred.life)\n\nLicensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) or the [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)), at your option. See the [`COPYRIGHT`](COPYRIGHT) file for more details.\n\n`SPDX-License-Identifier: (Apache-2.0 OR MIT)`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoul%2Fu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoul%2Fu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoul%2Fu/lists"}