├── .dockerignore ├── .github ├── FUNDING.yml └── workflows │ ├── codeql-analysis.yml │ └── unit-test.yml ├── .gitignore ├── .golangci.yml ├── CONTRIBUTING.md ├── Dockerfile ├── Dockerfile.doc ├── LICENSE.md ├── Makefile ├── README.md ├── all.go ├── all_test.go ├── any.go ├── any_test.go ├── contains.go ├── contains_test.go ├── count.go ├── count_test.go ├── difference.go ├── difference_test.go ├── docs ├── .hugo_build.lock ├── archetypes │ └── default.md ├── config.toml ├── content │ ├── _index.md │ ├── collections │ │ ├── all.md │ │ ├── any.md │ │ ├── contains.md │ │ ├── difference.md │ │ ├── drop.md │ │ ├── each.md │ │ ├── filter.md │ │ ├── find.md │ │ ├── flatmap.md │ │ ├── groupby.md │ │ ├── intersection.md │ │ ├── last.md │ │ ├── map.md │ │ ├── max.md │ │ ├── min.md │ │ ├── partition.md │ │ ├── reduce.md │ │ ├── sum.md │ │ └── unique.md │ ├── pipe │ │ └── new_pipe.md │ └── usage │ │ └── start.md ├── data │ └── menu │ │ ├── extra.yaml │ │ └── more.yaml ├── static │ └── logo.png └── themes │ └── hugo-geekdoc │ ├── LICENSE │ ├── README.md │ ├── VERSION │ ├── archetypes │ ├── docs.md │ └── posts.md │ ├── assets │ ├── search │ │ ├── config.json │ │ └── data.json │ └── sprites │ │ └── geekdoc.svg │ ├── data │ └── assets.json │ ├── i18n │ ├── de.yaml │ └── en.yaml │ ├── images │ ├── readme.png │ ├── screenshot.png │ └── tn.png │ ├── layouts │ ├── 404.html │ ├── _default │ │ ├── _markup │ │ │ ├── render-heading.html │ │ │ ├── render-image.html │ │ │ └── render-link.html │ │ ├── baseof.html │ │ ├── list.html │ │ ├── single.html │ │ ├── taxonomy.html │ │ └── terms.html │ ├── partials │ │ ├── foot.html │ │ ├── head │ │ │ ├── custom.html │ │ │ ├── favicons.html │ │ │ ├── meta.html │ │ │ ├── microformats.html │ │ │ ├── others.html │ │ │ └── rel-me.html │ │ ├── language.html │ │ ├── menu-bundle.html │ │ ├── menu-extra.html │ │ ├── menu-filetree.html │ │ ├── menu-nextprev.html │ │ ├── menu.html │ │ ├── microformats │ │ │ ├── opengraph.html │ │ │ ├── schema.html │ │ │ └── twitter_cards.html │ │ ├── page-header.html │ │ ├── posts │ │ │ └── metadata.html │ │ ├── search.html │ │ ├── site-footer.html │ │ ├── site-header.html │ │ ├── svg-icon-symbols.html │ │ └── utils │ │ │ ├── content.html │ │ │ ├── description.html │ │ │ ├── featured.html │ │ │ └── title.html │ ├── posts │ │ ├── list.html │ │ └── single.html │ ├── robots.txt │ └── shortcodes │ │ ├── button.html │ │ ├── columns.html │ │ ├── expand.html │ │ ├── hint.html │ │ ├── icon.html │ │ ├── img.html │ │ ├── include.html │ │ ├── katex.html │ │ ├── mermaid.html │ │ ├── tab.html │ │ ├── tabs.html │ │ ├── toc-tree.html │ │ └── toc.html │ ├── static │ ├── brand.svg │ ├── custom.css │ ├── favicon │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-256x256.png │ │ ├── android-chrome-36x36.png │ │ ├── android-chrome-384x384.png │ │ ├── android-chrome-48x48.png │ │ ├── android-chrome-512x512.png │ │ ├── android-chrome-72x72.png │ │ ├── android-chrome-96x96.png │ │ ├── apple-touch-icon-1024x1024.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-167x167.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── apple-touch-startup-image-1125x2436.png │ │ ├── apple-touch-startup-image-1136x640.png │ │ ├── apple-touch-startup-image-1242x2208.png │ │ ├── apple-touch-startup-image-1242x2688.png │ │ ├── apple-touch-startup-image-1334x750.png │ │ ├── apple-touch-startup-image-1536x2048.png │ │ ├── apple-touch-startup-image-1620x2160.png │ │ ├── apple-touch-startup-image-1668x2224.png │ │ ├── apple-touch-startup-image-1668x2388.png │ │ ├── apple-touch-startup-image-1792x828.png │ │ ├── apple-touch-startup-image-2048x1536.png │ │ ├── apple-touch-startup-image-2048x2732.png │ │ ├── apple-touch-startup-image-2160x1620.png │ │ ├── apple-touch-startup-image-2208x1242.png │ │ ├── apple-touch-startup-image-2224x1668.png │ │ ├── apple-touch-startup-image-2388x1668.png │ │ ├── apple-touch-startup-image-2436x1125.png │ │ ├── apple-touch-startup-image-2688x1242.png │ │ ├── apple-touch-startup-image-2732x2048.png │ │ ├── apple-touch-startup-image-640x1136.png │ │ ├── apple-touch-startup-image-750x1334.png │ │ ├── apple-touch-startup-image-828x1792.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-48x48.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── firefox_app_128x128.png │ │ ├── firefox_app_512x512.png │ │ ├── firefox_app_60x60.png │ │ ├── manifest.json │ │ ├── manifest.webapp │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ └── mstile-70x70.png │ ├── fonts │ │ ├── GeekdocIcons.woff │ │ ├── GeekdocIcons.woff2 │ │ ├── KaTeX_AMS-Regular.woff │ │ ├── KaTeX_AMS-Regular.woff2 │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ ├── KaTeX_Fraktur-Bold.woff │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ ├── KaTeX_Fraktur-Regular.woff │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ ├── KaTeX_Main-Bold.woff │ │ ├── KaTeX_Main-Bold.woff2 │ │ ├── KaTeX_Main-BoldItalic.woff │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ ├── KaTeX_Main-Italic.woff │ │ ├── KaTeX_Main-Italic.woff2 │ │ ├── KaTeX_Main-Regular.woff │ │ ├── KaTeX_Main-Regular.woff2 │ │ ├── KaTeX_Math-BoldItalic.woff │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ ├── KaTeX_Math-Italic.woff │ │ ├── KaTeX_Math-Italic.woff2 │ │ ├── KaTeX_SansSerif-Bold.woff │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ ├── KaTeX_SansSerif-Italic.woff │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ ├── KaTeX_SansSerif-Regular.woff │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ ├── KaTeX_Script-Regular.woff │ │ ├── KaTeX_Script-Regular.woff2 │ │ ├── KaTeX_Size1-Regular.woff │ │ ├── KaTeX_Size1-Regular.woff2 │ │ ├── KaTeX_Size2-Regular.woff │ │ ├── KaTeX_Size2-Regular.woff2 │ │ ├── KaTeX_Size3-Regular.woff │ │ ├── KaTeX_Size3-Regular.woff2 │ │ ├── KaTeX_Size4-Regular.woff │ │ ├── KaTeX_Size4-Regular.woff2 │ │ ├── KaTeX_Typewriter-Regular.woff │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ ├── LiberationMono.woff │ │ ├── LiberationMono.woff2 │ │ ├── LiberationSans-Bold.woff │ │ ├── LiberationSans-Bold.woff2 │ │ ├── LiberationSans-BoldItalic.woff │ │ ├── LiberationSans-BoldItalic.woff2 │ │ ├── LiberationSans-Italic.woff │ │ ├── LiberationSans-Italic.woff2 │ │ ├── LiberationSans.woff │ │ ├── LiberationSans.woff2 │ │ ├── Metropolis.woff │ │ └── Metropolis.woff2 │ ├── js │ │ ├── 116-d8286ca2.chunk.min.js │ │ ├── 273-3d271af5.chunk.min.js │ │ ├── 273-3d271af5.chunk.min.js.LICENSE.txt │ │ ├── katex-0ad34d3f.bundle.min.js │ │ ├── main-16c4e2c7.bundle.min.js │ │ ├── main-16c4e2c7.bundle.min.js.LICENSE.txt │ │ ├── mermaid-7da67bd0.bundle.min.js │ │ ├── search-1c4cfb2d.bundle.min.js │ │ └── search-1c4cfb2d.bundle.min.js.LICENSE.txt │ ├── katex-e264b2b5.min.css │ ├── main-daf4fc22.min.css │ ├── mobile-1d04b92f.min.css │ └── print-19966b38.min.css │ └── theme.toml ├── drop.go ├── drop_test.go ├── each.go ├── each_test.go ├── examples ├── filterMapReduce.go ├── filterMapReduce_test.go ├── pipe.go └── pipe_test.go ├── filter.go ├── filter_test.go ├── find.go ├── find_test.go ├── flatmap.go ├── flatmap_test.go ├── go.mod ├── go.sum ├── groupby.go ├── groupby_test.go ├── intersection.go ├── intersection_test.go ├── join.go ├── join_test.go ├── last.go ├── last_test.go ├── map.go ├── map_test.go ├── maps ├── map.go └── map_test.go ├── max.go ├── max_test.go ├── min.go ├── min_test.go ├── orderBy.go ├── orderBy_test.go ├── partition.go ├── partition_test.go ├── pipe.go ├── pipe_test.go ├── pointers.go ├── pointers_test.go ├── range.go ├── range_test.go ├── reduce.go ├── reduce_test.go ├── result.go ├── result_test.go ├── slices.go ├── slices_test.go ├── sum.go ├── sum_test.go ├── ternary.go ├── ternary_test.go ├── tuple.go ├── unique.go ├── unique_test.go ├── zip.go └── zip_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /docs 3 | *.md 4 | .git* 5 | .idea/ 6 | .golangci.yml 7 | coverage.out 8 | .trivycache/ 9 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: rjNemo 2 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | schedule: 8 | - cron: '24 15 * * 6' 9 | jobs: 10 | analyze: 11 | name: Analyze 12 | runs-on: ubuntu-latest 13 | permissions: 14 | actions: read 15 | contents: read 16 | security-events: write 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | language: [ 'go' ] 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v2 24 | - name: Initialize CodeQL 25 | uses: github/codeql-action/init@v1 26 | with: 27 | languages: ${{ matrix.language }} 28 | - name: Autobuild 29 | uses: github/codeql-action/autobuild@v1 30 | - name: Perform CodeQL Analysis 31 | uses: github/codeql-action/analyze@v1 32 | -------------------------------------------------------------------------------- /.github/workflows/unit-test.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push, pull_request] 3 | jobs: 4 | build: 5 | name: Build 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@master 9 | with: 10 | fetch-depth: 2 11 | - uses: actions/setup-go@v4 12 | with: 13 | go-version: "1.23" 14 | - name: Run tests with coverage 15 | run: go test -coverprofile=coverage.out -covermode=count ./... 16 | - uses: codecov/codecov-action@v4 17 | with: 18 | token: ${{ secrets.CODECOV_TOKEN }} 19 | files: ./coverage.out 20 | flags: unittests 21 | name: codecov-umbrella 22 | fail_ci_if_error: true 23 | verbose: true 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | !.vscode/settings.json 3 | !.vscode/tasks.json 4 | !.vscode/launch.json 5 | !.vscode/extensions.json 6 | *.code-workspace 7 | .history/ 8 | .idea/ 9 | cmake-build-*/ 10 | *.iws 11 | out/ 12 | .idea_modules/ 13 | atlassian-ide-plugin.xml 14 | com_crashlytics_export_strings.xml 15 | crashlytics.properties 16 | crashlytics-build.properties 17 | fabric.properties 18 | *~ 19 | .fuse_hidden* 20 | .directory 21 | .Trash-* 22 | .nfs* 23 | *.exe 24 | *.exe~ 25 | *.dll 26 | *.so 27 | *.dylib 28 | *.test 29 | *.out 30 | Thumbs.db 31 | Thumbs.db:encryptable 32 | ehthumbs.db 33 | ehthumbs_vista.db 34 | *.stackdump 35 | [Dd]esktop.ini 36 | $RECYCLE.BIN/ 37 | *.cab 38 | *.msi 39 | *.msix 40 | *.msm 41 | *.msp 42 | *.lnk 43 | .DS_Store 44 | .AppleDouble 45 | .LSOverride 46 | Icon 47 | ._* 48 | .DocumentRevisions-V100 49 | .fseventsd 50 | .Spotlight-V100 51 | .TemporaryItems 52 | .Trashes 53 | .VolumeIcon.icns 54 | .com.apple.timemachine.donotpresent 55 | .AppleDB 56 | .AppleDesktop 57 | Network Trash Folder 58 | Temporary Items 59 | .apdisk 60 | docs/public 61 | .trivycache/ 62 | .vscode/launch.json 63 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | skip-dirs-use-default: true 2 | 3 | run: 4 | timeout: 5m 5 | 6 | linters: 7 | enable: 8 | - bodyclose 9 | - deadcode 10 | - depguard 11 | - dogsled 12 | - errcheck 13 | - errorlint 14 | - exportloopref 15 | - gocritic 16 | - gocyclo 17 | - gofmt 18 | - goimports 19 | - goprintffuncname 20 | - gosimple 21 | - gosec 22 | - govet 23 | - ineffassign 24 | - misspell 25 | - noctx 26 | - nolintlint 27 | - prealloc 28 | - rowserrcheck 29 | - staticcheck 30 | - structcheck 31 | - stylecheck 32 | - typecheck 33 | - unconvert 34 | - unparam 35 | - unused 36 | - varcheck 37 | - whitespace 38 | fast: true 39 | 40 | linters-settings: 41 | goimports: 42 | local-prefixes: github.com/rjNemo/underscore -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other 4 | method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 11 | 2. Update the README.md with details of changes to the interface, this includes new environment variables, exposed 12 | ports, useful file locations and container parameters. 13 | 3. Increase the version numbers in any examples files and the README.md to the new version that this Pull Request would 14 | represent. The versioning scheme we use is [SemVer](http://semver.org/). 15 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you do not have 16 | permission to do that, you may request the second reviewer to merge it for you. 17 | 18 | ## Code of Conduct 19 | 20 | ### Our Pledge 21 | 22 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making 23 | participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, 24 | disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, 25 | religion, or sexual identity and orientation. 26 | 27 | ### Our Standards 28 | 29 | Examples of behavior that contributes to creating a positive environment include: 30 | 31 | - Using welcoming and inclusive language 32 | - Being respectful of differing viewpoints and experiences 33 | - Gracefully accepting constructive criticism 34 | - Focusing on what is best for the community 35 | - Showing empathy towards other community members 36 | 37 | Examples of unacceptable behavior by participants include: 38 | 39 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 40 | - Trolling, insulting/derogatory comments, and personal or political attacks 41 | - Public or private harassment 42 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 43 | - Other conduct which could reasonably be considered inappropriate in a professional setting 44 | 45 | ### Our Responsibilities 46 | 47 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take 48 | appropriate and fair corrective action in response to any instances of unacceptable behavior. 49 | 50 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, 51 | issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any 52 | contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 53 | 54 | ### Scope 55 | 56 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the 57 | project or its community. Examples of representing a project or community include using an official project e-mail 58 | address, posting via an official social media account, or acting as an appointed representative at an online or offline 59 | event. Representation of a project may be further defined and clarified by project maintainers. 60 | 61 | ### Enforcement 62 | 63 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team 64 | at [nemausatpro@gmail.com]. All complaints will be reviewed and investigated and will result in a response that is 65 | deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with 66 | regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 67 | 68 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent 69 | repercussions as determined by other members of the project's leadership. 70 | 71 | ### Attribution 72 | 73 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available 74 | at [http://contributor-covenant.org/version/1/4][version] 75 | 76 | [homepage]: http://contributor-covenant.org 77 | 78 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23-alpine 2 | 3 | ENV CGO_ENABLED 0 4 | ENV GOOS linux 5 | ENV GOARCH amd64 6 | 7 | RUN apk upgrade --no-cache 8 | 9 | WORKDIR /lib 10 | 11 | COPY go.* ./ 12 | RUN go mod download 13 | 14 | COPY . ./ 15 | -------------------------------------------------------------------------------- /Dockerfile.doc: -------------------------------------------------------------------------------- 1 | FROM golang:1.23-alpine AS builder 2 | 3 | ENV CGO_ENABLED=0 4 | ENV GOOS=linux 5 | ENV GOARCH=amd64 6 | 7 | RUN apk -U upgrade --no-cache 8 | RUN apk add hugo 9 | 10 | WORKDIR /docs 11 | 12 | COPY go.* ./ 13 | RUN go mod download 14 | 15 | COPY . . 16 | 17 | RUN hugo --gc --minify 18 | 19 | FROM scratch 20 | 21 | COPY --from=builder /docs/public /public 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Ruidy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TEST=go test ./... 2 | COVER=-coverpkg=./... -coverprofile cov.out -covermode=count; go tool cover -func cov.out; rm cov.out 3 | IMAGE=underscore 4 | 5 | build: 6 | docker build -t $(IMAGE):latest . 7 | 8 | test: build 9 | docker run --name $(IMAGE) --rm -i -t $(IMAGE) sh -c "$(TEST) $(COVER)" 10 | 11 | scan: 12 | trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --severity CRITICAL $(IMAGE) 13 | 14 | scan-config: 15 | trivy config . 16 | 17 | .PHONY: docs 18 | docs: 19 | cd docs && hugo server -D 20 | 21 | build-docs: 22 | cd docs && hugo --gc --minify 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # \_Underscore 2 | 3 | ![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge) 4 | [![Go version](https://img.shields.io/github/go-mod/go-version/rjNemo/underscore?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/rjNemo/underscore) 5 | ![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge) 6 | ![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov) 7 | [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9726/badge?style=for-the-badge)](https://www.bestpractices.dev/projects/9726) 8 | 9 | ![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&font=KoHo&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FrjNemo%2Funderscore%2Fmain%2Fdocs%2Fstatic%2Flogo.png&owner=1&pattern=Floating%20Cogs&stargazers=1&theme=Dark) 10 | 11 | `underscore` is a `Go` library providing useful functional programming helpers without 12 | extending any built-in objects. 13 | 14 | It is mostly a port from the `underscore.js` library based on generics brought by 15 | `Go 1.18`. 16 | 17 | ## Usage 18 | 19 | 📚 Follow this link for the [documentation](https://underscore.onrender.com/). 20 | 21 | Install the library using 22 | 23 | ```shell 24 | go get github.com/rjNemo/underscore@0.4.0 25 | ``` 26 | 27 | Please check out the [examples](examples) to see how to use the library. 28 | 29 | ```go 30 | package main 31 | 32 | import ( 33 | "fmt" 34 | u "github.com/rjNemo/underscore" 35 | ) 36 | 37 | func main() { 38 | numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 39 | // filter even numbers from the slice 40 | evens := u.Filter(numbers, func(n int) bool { return n%2 == 0 }) 41 | // square every number in the slice 42 | squares := u.Map(evens, func(n int) int { return n * n }) 43 | // reduce to the sum 44 | res := u.Reduce(squares, func(n, acc int) int { return n + acc }, 0) 45 | 46 | fmt.Println(res) // 120 47 | } 48 | ``` 49 | 50 | ## Getting Started 51 | 52 | These instructions will get you a copy of the project up and running on your local 53 | machine for development and testing purposes. 54 | 55 | ### Prerequisites 56 | 57 | You need at least `go1.18` for development. The project is shipped with a [Dockerfile](Dockerfile) 58 | based on `go1.18`. 59 | 60 | If you prefer local development, navigate to the [official 61 | download page](https://go.dev/dl/) and install version `1.18` or beyond. 62 | 63 | ### Installing 64 | 65 | First clone the repository 66 | 67 | ```shell 68 | git clone https://github.com/rjNemo/underscore.git 69 | ``` 70 | 71 | Install dependencies 72 | 73 | ```shell 74 | go mod download 75 | ``` 76 | 77 | And that's it. 78 | 79 | ## Tests 80 | 81 | To run the unit tests, you can simply run: 82 | 83 | ```shell 84 | make test 85 | ``` 86 | 87 | ## Functions 88 | 89 | `underscore` provides many of functions that support your favorite functional helpers 90 | 91 | ### Collections 92 | 93 | - `All` 94 | - `Any` 95 | - `Contains` (only numerics values at the moment) 96 | - `Each` 97 | - `Filter` 98 | - `Flatmap` 99 | - `GroupBy` 100 | - `Find` 101 | - `Map` 102 | - `Max` 103 | - `Min` 104 | - `Partition` 105 | - `Reduce` 106 | 107 | ### Pipe 108 | 109 | Calling `NewPipe` will cause all future method calls to return wrapped values. When 110 | you've finished the computation, call `Value` to retrieve the final value. 111 | 112 | Methods not returning a slice such as `Reduce`, `All`, `Any`, will break the `Chain` 113 | and return `Value` instantly. 114 | 115 | ## Built With 116 | 117 | - [Go](https://go.dev/) - Build fast, reliable, and efficient software at scale 118 | 119 | ## Contributing 120 | 121 | Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, 122 | and the process for submitting pull requests to us. 123 | 124 | ## Versioning 125 | 126 | We use [SemVer](http://semver.org/) for versioning. For the versions available, see 127 | the [tags on this repository](https://github.com/rjNemo/underscore/tags). 128 | 129 | ## Authors 130 | 131 | - **Ruidy** - _Initial work_ - [Ruidy](https://github.com/rjNemo) 132 | 133 | See also the list of [contributors](https://github.com/rjNemo/underscore/contributors) 134 | who participated in this project. 135 | 136 | ## License 137 | 138 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) 139 | file for details 140 | 141 | ## Acknowledgments 142 | 143 | This project is largely inspired by [Underscore.js](https://underscorejs.org/#) 144 | library. Check out the original project if you don't already know it. 145 | -------------------------------------------------------------------------------- /all.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // All returns true if all the values in the slice pass the predicate truth test. 4 | // Short-circuits and stops traversing the slice if a false element is found. 5 | func All[T any](values []T, predicate func(T) bool) bool { 6 | for _, v := range values { 7 | if !predicate(v) { 8 | return false 9 | } 10 | } 11 | return true 12 | } 13 | -------------------------------------------------------------------------------- /all_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestAll(t *testing.T) { 12 | nums := []int{1, 3, 5, 7, 9} 13 | isOdd := func(n int) bool { return n%2 != 0 } 14 | assert.True(t, u.All(nums, isOdd)) 15 | } 16 | 17 | func TestNotAll(t *testing.T) { 18 | nums := []int{1, 3, 5, 7, 9, 10} 19 | isOdd := func(n int) bool { return n%2 != 0 } 20 | assert.False(t, u.All(nums, isOdd)) 21 | } 22 | -------------------------------------------------------------------------------- /any.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Any returns true if any of the values in the slice pass the predicate truth test. 4 | // Short-circuits and stops traversing the slice if a true element is found. 5 | func Any[T any](values []T, predicate func(T) bool) bool { 6 | for _, v := range values { 7 | if predicate(v) { 8 | return true 9 | } 10 | } 11 | return false 12 | } 13 | -------------------------------------------------------------------------------- /any_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestSome(t *testing.T) { 12 | nums := []int{1, 2, 4, 6, 8} 13 | isOdd := func(n int) bool { return n%2 != 0 } 14 | 15 | assert.True(t, u.Any(nums, isOdd)) 16 | } 17 | 18 | func TestNotSome(t *testing.T) { 19 | nums := []int{2, 4, 6, 8} 20 | isOdd := func(n int) bool { return n%2 != 0 } 21 | 22 | assert.False(t, u.Any(nums, isOdd)) 23 | } 24 | -------------------------------------------------------------------------------- /contains.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Contains returns true if the value is present in the slice 4 | func Contains[T comparable](values []T, value T) bool { 5 | for _, v := range values { 6 | if v == value { 7 | return true 8 | } 9 | } 10 | return false 11 | } 12 | -------------------------------------------------------------------------------- /contains_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestContains(t *testing.T) { 12 | nums := []int{1, 3, 5, 7, 9} 13 | assert.True(t, u.Contains(nums, 5)) 14 | } 15 | 16 | func TestNotContains(t *testing.T) { 17 | nums := []int{1, 3, 5, 7, 9} 18 | assert.False(t, u.Contains(nums, 15)) 19 | } 20 | -------------------------------------------------------------------------------- /count.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Count returns the number of elements in the slice that satisfy the predicate. 4 | // example: Count([]int{1,2,3,4,5}, func(n int) bool { return n%2 == 0 }) // 2 5 | func Count[T any](slice []T, predicate func(T) bool) int { 6 | count := 0 7 | for _, item := range slice { 8 | if predicate(item) { 9 | count++ 10 | } 11 | } 12 | return count 13 | } 14 | -------------------------------------------------------------------------------- /count_test.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func Test_Count_Can_Count_Numbers(t *testing.T) { 11 | numbers := Range(1, 100) 12 | count := Count(numbers, func(n int) bool { 13 | return n%2 == 0 14 | }) 15 | 16 | assert.Equal(t, 50, count) 17 | } 18 | 19 | type People struct { 20 | Name string 21 | Age int 22 | Gender string 23 | } 24 | 25 | func Test_Count_Can_Count_People(t *testing.T) { 26 | people := []People{ 27 | {Name: "Andy", Age: 43, Gender: "M"}, 28 | {Name: "Fred", Age: 33, Gender: "M"}, 29 | {Name: "Jack", Age: 23, Gender: "M"}, 30 | {Name: "Jill", Age: 43, Gender: "F"}, 31 | {Name: "Anna", Age: 33, Gender: "F"}, 32 | {Name: "Arya", Age: 23, Gender: "F"}, 33 | {Name: "Jane", Age: 13, Gender: "F"}, 34 | } 35 | 36 | a := Count(people, func(p People) bool { 37 | return strings.HasPrefix(p.Name, "A") 38 | }) 39 | assert.Equal(t, 3, a) 40 | 41 | females := Count(people, func(p People) bool { 42 | return p.Gender == "F" 43 | }) 44 | assert.Equal(t, 4, females) 45 | 46 | males := Count(people, func(p People) bool { 47 | return p.Gender == "M" 48 | }) 49 | assert.Equal(t, 3, males) 50 | 51 | over30 := Count(people, func(p People) bool { 52 | return p.Age > 30 53 | }) 54 | assert.Equal(t, 4, over30) 55 | 56 | under30 := Count(people, func(p People) bool { 57 | return p.Age < 30 58 | }) 59 | assert.Equal(t, 3, under30) 60 | 61 | under20 := Count(people, func(p People) bool { 62 | return p.Age < 20 63 | }) 64 | assert.Equal(t, 1, under20) 65 | } 66 | -------------------------------------------------------------------------------- /difference.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Difference Returns a copy of the array with all instances of the values that are not present in the other array. 4 | func Difference[T comparable](slice, other []T) []T { 5 | return Filter(slice, func(n T) bool { 6 | return !Contains(other, n) 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /difference_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestDifference(t *testing.T) { 12 | nums := []int{1, 3, 5, 6, 7, 9} 13 | reject := []int{9, 7, 5, 4} 14 | want := []int{1, 3, 6} 15 | 16 | assert.Equal(t, want, u.Difference(nums, reject)) 17 | } 18 | -------------------------------------------------------------------------------- /docs/.hugo_build.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/.hugo_build.lock -------------------------------------------------------------------------------- /docs/archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /docs/config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://underscore.onrender.com/" 2 | title = "underscore" 3 | theme = "hugo-geekdoc" 4 | 5 | pluralizeListTitles = false 6 | 7 | # Geekdoc required configuration 8 | pygmentsUseClasses = true 9 | pygmentsCodeFences = true 10 | disablePathToLower = true 11 | 12 | # Required if you want to render robots.txt template 13 | enableRobotsTXT = true 14 | 15 | # Needed for mermaid shortcodes 16 | [markup] 17 | [markup.goldmark.renderer] 18 | # Needed for mermaid shortcode 19 | unsafe = true 20 | [markup.tableOfContents] 21 | startLevel = 1 22 | endLevel = 9 23 | 24 | [taxonomies] 25 | tag = "tags" -------------------------------------------------------------------------------- /docs/content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: _Underscore 3 | --- 4 | 5 | ![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge) 6 | [![Go version](https://img.shields.io/github/go-mod/go-version/rjNemo/underscore?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/rjNemo/underscore) 7 | ![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge) 8 | ![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov) 9 | 10 | ![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&font=KoHo&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FrjNemo%2Funderscore%2Fmain%2Fdocs%2Fstatic%2Flogo.png&owner=1&pattern=Floating%20Cogs&stargazers=1&theme=Dark) 11 | 12 | `underscore` is a `Go` library providing useful functional programming helpers without 13 | extending any built-in objects. 14 | 15 | It is mostly a port from the `underscore.js` library based on generics available 16 | from `go1.18`. 17 | 18 | ## Quick Start 19 | 20 | Install the library using 21 | 22 | ```shell 23 | go get github.com/rjNemo/underscore 24 | ``` 25 | 26 | Please check out the [examples](https://github.com/rjNemo/underscore/tree/main/examples) 27 | to see how to use the library. 28 | 29 | ```go 30 | package main 31 | 32 | import ( 33 | "fmt" 34 | u "github.com/rjNemo/underscore" 35 | ) 36 | 37 | func main() { 38 | numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 39 | // filter even numbers from the slice 40 | evens := u.Filter(numbers, func(n int) bool { return n%2 == 0 }) 41 | // square every number in the slice 42 | squares := u.Map(evens, func(n int) int { return n * n }) 43 | // reduce to the sum 44 | res := u.Reduce(squares, func(n, acc int) int { return n + acc }, 0) 45 | 46 | fmt.Println(res) // 120 47 | } 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/content/collections/all.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "All" 3 | date: 2021-12-30T13:24:39-04:00 4 | --- 5 | 6 | `All` returns true if all the values in the slice pass the predicate truth test.\ 7 | Short-circuits and stops traversing the slice if a false element is found. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 3, 5, 7, 9} 19 | isOdd := func(n int) bool { return n%2 != 0 } 20 | fmt.Println(u.All(nums, isOdd)) // true 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/collections/any.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Any" 3 | date: 2022-03-21T13:26:01-04:00 4 | --- 5 | 6 | `Any` returns true if any of the values in the slice pass the predicate truth test. Short-circuits and stops traversing 7 | the slice if a true element is found. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 2, 4, 6, 8} 19 | isEven := func(n int) bool { return n%2 == 0 } 20 | fmt.Println(u.Any(nums, isEven)) // true 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/collections/contains.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Contains" 3 | date: 2022-03-21T13:30:29-04:00 4 | --- 5 | 6 | `Contains` returns true if the value is present in the slice. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{1, 3, 5, 7, 9} 18 | 19 | fmt.Println(u.Contains(nums, 5)) // true 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/difference.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Difference" 3 | date: 2022-03-21T13:48:21-04:00 4 | --- 5 | 6 | Returns a copy of the array with all instances of the values that are not present in the other arrays. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{1, 3, 5, 6, 7, 9} 18 | reject := []int{9, 7, 5, 4} 19 | 20 | fmt.Println(u.Difference(nums, reject)) // {1, 3, 6} 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/collections/drop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Drop" 3 | date: 2022-03-21T13:48:21-04:00 4 | --- 5 | 6 | `Drop` returns the rest of the elements in a slice. Pass an index to return the values of the slice from that index 7 | onward. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 19 | 20 | fmt.Println(u.Drop(nums, 3)) // {1, 9, 2, 3, 7, 4, 6, 5} 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/collections/each.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Each" 3 | date: 2022-03-21T13:30:59-04:00 4 | --- 5 | 6 | `Each` iterates over a slice of elements, yielding each in turn to an action function. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | names := []string{"Alice", "Bob", "Charles"} 18 | res := make([]string, 0) 19 | 20 | u.Each(names, func(n string) { 21 | res = append(res, fmt.Sprintf("Hi %s", n)) 22 | }) 23 | fmt.Println(res) // {"Hi Alice", "Hi Bob", "Hi Charles"} 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/content/collections/filter.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Filter" 3 | date: 2022-03-21T13:31:21-04:00 4 | --- 5 | 6 | `Filter` looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate). 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 18 | isEven := func(n int) bool { return n%2 == 0 } 19 | fmt.Println(u.Filter(nums, isEven)) // {0, 2, 4, 6, 8} 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/find.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Find" 3 | date: 2022-03-21T13:31:40-04:00 4 | --- 5 | 6 | Find looks through each value in the slice, returning the first one that passes a truth test (predicate), or the default 7 | value for the type and an error if no value passes the test. The function returns as soon as it finds an acceptable 8 | element, and doesn't traverse the entire slice. 9 | 10 | ```go 11 | package main 12 | 13 | import ( 14 | "fmt" 15 | u "github.com/rjNemo/underscore" 16 | ) 17 | 18 | func main() { 19 | nums := []int{2, 4, 5, 6, 8, 0} 20 | isOdd := func(n int) bool { return n%2 != 0 } 21 | 22 | n, err := u.Find(nums, isOdd) 23 | fmt.Println(n) // 5 24 | fmt.Println(err) // nil 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/content/collections/flatmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Flatmap" 3 | date: 2022-08-10T16:49:56+02:00 4 | draft: false 5 | --- 6 | 7 | Flatmap flattens the input slice element into the new slice. FlatMap maps every element with the help of a mapper function, then flattens the input slice element into the new slice. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 2, 3, 4} 19 | mapper := func(n int) []int { return []int{(n - 1) * n, (n) * n} } 20 | res := u.Flatmap(nums, mapper) 21 | fmt.Println(res) // {0, 1, 2, 4, 6, 9, 12, 16} 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/collections/groupby.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Group by" 3 | date: 2023-06-07T00:49:56+02:00 4 | --- 5 | 6 | GroupBy splits a slice into a map[K][]V grouped by the result of the iterator function. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []float64{1.3, 2.1, 2.4} 18 | groupingFunc := func(n float64) int { return int(math.Floor(n)) } 19 | res := u.GroupBy(nums, groupingFunc) // { 1: {1.3}, 2: {2.1, 2.4}} 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/intersection.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Intersection" 3 | date: 2022-03-27T00:24:11-04:00 4 | --- 5 | 6 | Intersection computes the list of values that are the intersection of all the slices. 7 | Each value in the result is present in each of the slices. 8 | 9 | ```go 10 | package main 11 | 12 | 13 | import ( 14 | "fmt" 15 | u "github.com/rjNemo/underscore" 16 | ) 17 | 18 | func main(){ 19 | a := []int{1, 3, 5, 7, 9} 20 | b := []int{2, 3, 5, 8, 0} 21 | 22 | fmt.Println(u.Intersection(a, b)) // {3, 5} 23 | } 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /docs/content/collections/last.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Last" 3 | date: 2022-03-21T13:46:24-04:00 4 | --- 5 | 6 | `Last` returns the last element of the slice. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 18 | 19 | fmt.Println(u.Last(nums)) // 5 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/map.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Map" 3 | date: 2022-03-21T13:32:10-04:00 4 | --- 5 | 6 | `Map` produces a new slice of values by mapping each value in the slice through a transform function. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{1, 2, 3} 18 | toSquare := func(n int) int { 19 | return n * n 20 | } 21 | fmt.Println(u.Map(nums, toSquare)) // {1, 4, 9} 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/content/collections/max.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Max" 3 | date: 2022-03-21T13:32:43-04:00 4 | --- 5 | 6 | `Max` returns the maximum value in the slice. This function can currently only compare numbers reliably. This function 7 | uses operator `<`. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 19 | fmt.Println(u.Max(nums)) // 9 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/min.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Min" 3 | date: 2022-03-21T13:33:03-04:00 4 | --- 5 | 6 | `Min` returns the minimum value in the slice. This function can currently only compare numbers reliably. This function 7 | uses operator `<`. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 19 | fmt.Println(u.Min(nums)) // 1 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/partition.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Partition" 3 | date: 2022-03-21T13:33:23-04:00 4 | --- 5 | 6 | `Partition` splits the slice into two slices: one whose elements all satisfy predicate and one whose elements all do not 7 | satisfy predicate. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 19 | isEven := func(n int) bool { return n%2 == 0 } 20 | 21 | evens, odds := u.Partition(nums, isEven) 22 | fmt.Println(evens) // {0, 2, 4, 6, 8} 23 | fmt.Println(odds) // {1, 3, 5, 7, 9} 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/content/collections/reduce.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Reduce" 3 | date: 2022-03-21T13:33:52-04:00 4 | --- 5 | 6 | `Reduce` combine a list of values into a single value. `acc` is the initial state, and each successive step of it should 7 | be returned by the reduction function. 8 | 9 | ```go 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | u "github.com/rjNemo/underscore" 15 | ) 16 | 17 | func main() { 18 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 19 | sum := func(n, acc int) int { return n + acc } 20 | fmt.Println(u.Reduce(nums, sum, 0)) // 45 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/content/collections/sum.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Sum" 3 | date: 2022-03-21T13:50:29-04:00 4 | --- 5 | 6 | `Sum` adds elements of the slice. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 18 | 19 | fmt.Println(u.Sum(nums)) // 45 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/collections/unique.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Unique" 3 | date: 2022-04-12T17:18:04-04:00 4 | --- 5 | 6 | `Unique` returns a duplicate-free version of the slice. Only the first occurrence of each value is kept. 7 | 8 | ```go 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | u "github.com/rjNemo/underscore" 14 | ) 15 | 16 | func main() { 17 | nums := []int{1, 4, 2, 5, 3, 1, 5, 2, 8, 9} 18 | 19 | fmt.Println(u.Unique(nums)) // 1, 4, 2, 5, 3, 8, 9 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/content/pipe/new_pipe.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "NewPipe" 3 | date: 2021-12-31T13:11:41-04:00 4 | --- 5 | 6 | Calling `NewPipe` will cause all future method calls to return wrapped objects. 7 | When you've finished the computation, call `Value` to retrieve the final value. 8 | 9 | Methods not returning a collection such as `Reduce`, `All`, `Any`, will break the 10 | chain and return `Value` instantly. 11 | 12 | ```go 13 | package main 14 | 15 | import ( 16 | "fmt" 17 | u "github.com/rjNemo/underscore" 18 | ) 19 | 20 | func main() { 21 | sum := u.NewPipe([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). 22 | // filter even numbers from the slice 23 | Filter(func(n int) bool { return n%2 == 0 }). 24 | // square every number in the slice 25 | Map(func(n int) int { return n * n }). 26 | // reduce to the sum 27 | Reduce(func(n, acc int) int { return n + acc }, 0) 28 | 29 | fmt.Println(sum) // 120 30 | } 31 | ``` 32 | 33 | -------------------------------------------------------------------------------- /docs/content/usage/start.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started" 3 | date: 2022-03-21T14:09:01-04:00 4 | --- 5 | 6 | ## Quick Start 7 | 8 | Install the library using 9 | 10 | ```shell 11 | go get github.com/rjNemo/underscore 12 | ``` 13 | 14 | Please check out the [examples](https://github.com/rjNemo/underscore/tree/main/examples) 15 | to see how to use the library. 16 | 17 | ```go 18 | package main 19 | 20 | import ( 21 | "fmt" 22 | u "github.com/rjNemo/underscore" 23 | ) 24 | 25 | func main() { 26 | numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 27 | // filter even numbers from the slice 28 | evens := u.Filter(numbers, func(n int) bool { return n%2 == 0 }) 29 | // square every number in the slice 30 | squares := u.Map(evens, func(n int) int { return n * n }) 31 | // reduce to the sum 32 | res := u.Reduce(squares, func(n, acc int) int { return n + acc }, 0) 33 | 34 | fmt.Println(res) // 120 35 | } 36 | ``` 37 | 38 | ## Installation 39 | 40 | These instructions will get you a copy of the project up and running on your local 41 | machine for development and testing purposes. 42 | 43 | ### Prerequisites 44 | 45 | You need at least `go1.18` for development. The project is shipped with 46 | a [Dockerfile](https://github.com/rjNemo/underscore/tree/main/Dockerfile) based 47 | on `go1.18`. 48 | 49 | If you prefer local development, navigate to the [official 50 | download page](https://go.dev/dl/) and install version `1.18` or beyond. 51 | 52 | ### Installing 53 | 54 | First clone the repository 55 | 56 | ```shell 57 | git clone https://github.com/rjNemo/underscore.git 58 | ``` 59 | 60 | Install dependencies 61 | 62 | ```shell 63 | go mod download 64 | ``` 65 | 66 | And that's it. 67 | 68 | ## Tests 69 | 70 | To run the unit tests, you can simply run: 71 | 72 | ```shell 73 | make test 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/data/menu/extra.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | - name: GitHub 4 | ref: https://github.com/rjNemo/underscore 5 | icon: gdoc_github 6 | external: true -------------------------------------------------------------------------------- /docs/data/menu/more.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | more: 3 | - name: News 4 | ref: "/#" 5 | icon: "gdoc_notification" 6 | - name: Releases 7 | ref: "https://github.com/rjNemo/underscore/releases" 8 | external: true 9 | icon: "gdoc_download" 10 | - name: "View Source" 11 | ref: "https://github.com/rjNemo/underscore" 12 | external: true 13 | icon: "gdoc_github" -------------------------------------------------------------------------------- /docs/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/static/logo.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Robert Kaussow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice (including the next 13 | paragraph) shall be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 19 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 21 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/README.md: -------------------------------------------------------------------------------- 1 | # Geekdoc 2 | 3 | [![Build Status](https://img.shields.io/drone/build/thegeeklab/hugo-geekdoc?logo=drone&server=https%3A%2F%2Fdrone.thegeeklab.de)](https://drone.thegeeklab.de/thegeeklab/hugo-geekdoc) 4 | [![Hugo Version](https://img.shields.io/badge/hugo-0.83-blue.svg)](https://gohugo.io) 5 | [![GitHub release](https://img.shields.io/github/v/release/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/releases/latest) 6 | [![GitHub contributors](https://img.shields.io/github/contributors/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors) 7 | [![License: MIT](https://img.shields.io/github/license/thegeeklab/hugo-geekdoc)](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE) 8 | 9 | Geekdoc is a simple Hugo theme for documentations. It is intentionally designed as a fast and lean theme and may not fit the requirements of complex projects. If a more feature-complete theme is required there are a lot of good alternatives out there. You can find a demo and the full documentation at [https://geekdocs.de](https://geekdocs.de). 10 | 11 | ![Desktop and mobile preview](https://raw.githubusercontent.com/thegeeklab/hugo-geekdoc/main/images/readme.png) 12 | 13 | ## Build and release process 14 | 15 | This theme is subject to a CI driven build and release process common for software development. During the release build, all necessary assets are automatically built by [webpack](https://webpack.js.org/) and bundled in a release tarball. You can download the latest release from the GitHub [release page](https://github.com/thegeeklab/hugo-geekdoc/releases). 16 | 17 | Due to the fact that `webpack` and `npm scripts` are used as pre-processors, the theme cannot be used from the main branch by default. If you want to use the theme from a cloned branch instead of a release tarball you'll need to install `webpack` locally and run the build script once to create all required assets. 18 | 19 | ```Shell 20 | # install required packages from package.json 21 | npm install 22 | 23 | # run the build script to build required assets 24 | npm run build 25 | ``` 26 | 27 | See the [Getting Started Guide](https://geekdocs.de/usage/getting-started/) for details about the different setup options. 28 | 29 | ## Contributors 30 | 31 | Special thanks goes to all [contributors](https://github.com/thegeeklab/hugo-geekdoc/graphs/contributors). If you would like to contribute, 32 | please see the [instructions](https://github.com/thegeeklab/hugo-geekdoc/blob/main/CONTRIBUTING.md). 33 | 34 | Geekdoc is inspired and partially based on the [hugo-book](https://github.com/alex-shpak/hugo-book) theme, thanks [Alex Shpak](https://github.com/alex-shpak/) for your work. 35 | 36 | ## License 37 | 38 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE) file for details. 39 | 40 | The used SVG icons and generated icon fonts are licensed under the license of the respective icon pack: 41 | 42 | - Font Awesome: [CC BY 4.0 License](https://github.com/FortAwesome/Font-Awesome#license) 43 | - IcoMoon Free Pack: [GPL/CC BY 4.0](https://icomoon.io/#icons-icomoon) 44 | - Material Icons: [Apache License 2.0](https://github.com/google/material-design-icons/blob/main/LICENSE) 45 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/VERSION: -------------------------------------------------------------------------------- 1 | v0.27.5 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/archetypes/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ .Name | humanize | title }}" 3 | weight: 1 4 | # geekdocFlatSection: false 5 | # geekdocToc: 6 6 | # geekdocHidden: false 7 | --- 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/archetypes/posts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | --- 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/assets/search/config.json: -------------------------------------------------------------------------------- 1 | {{- $searchDataFile := printf "search/%s.data.json" .Language.Lang -}} 2 | {{- $searchData := resources.Get "search/data.json" | resources.ExecuteAsTemplate $searchDataFile . | resources.Minify -}} 3 | { 4 | "dataFile": {{ $searchData.RelPermalink | jsonify }}, 5 | "indexConfig": {{ .Site.Params.GeekdocSearchConfig | jsonify }}, 6 | "showParent": {{ if .Site.Params.GeekdocSearchShowParent }}true{{ else }}false{{ end }} 7 | } 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/assets/search/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | {{ range $index, $page := (where .Site.Pages "Params.GeekdocProtected" "ne" true) }} 3 | {{ if ne $index 0 }},{{ end }} 4 | { 5 | "id": {{ $index }}, 6 | "href": "{{ $page.RelPermalink }}", 7 | "title": {{ (partial "utils/title" $page) | jsonify }}, 8 | "parent": {{ with $page.Parent }}{{ (partial "utils/title" .) | jsonify }}{{ else }}""{{ end }}, 9 | "content": {{ $page.Plain | jsonify }} 10 | } 11 | {{ end }} 12 | ] 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/de.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Seite bearbeiten 3 | 4 | nav_navigation: Navigation 5 | nav_tags: Tags 6 | nav_more: Weitere 7 | nav_top: Nach oben 8 | 9 | form_placeholder_search: Suchen 10 | 11 | error_page_title: Verlaufen? Keine Sorge 12 | error_message_title: Verlaufen? 13 | error_message_code: Fehler 404 14 | error_message_text: > 15 | Wir können die Seite nach der Du gesucht hast leider nicht finden. Keine Sorge, 16 | wir bringen Dich zurück zur Startseite. 17 | 18 | button_toggle_dark: Wechsel zwischen Dunkel/Hell/Auto Modus 19 | button_nav_open: Navigation öffnen 20 | button_nav_close: Navigation schließen 21 | button_menu_open: Menüband öffnen 22 | button_menu_close: Menüband schließen 23 | button_homepage: Zurück zur Startseite 24 | 25 | title_anchor_prefix: "Link zu:" 26 | 27 | posts_read_more: Ganzen Artikel lesen 28 | posts_read_time: 29 | one: "Eine Minute Lesedauer" 30 | other: "{{ . }} Minuten Lesedauer" 31 | posts_update_prefix: Aktualisiert am 32 | posts_count: 33 | one: "Ein Artikel" 34 | other: "{{ . }} Artikel" 35 | posts_tagged_with: Alle Artikel mit dem Tag '{{ . }}' 36 | 37 | footer_build_with: > 38 | Entwickelt mit Hugo und 39 | 40 | footer_legal_notice: Impressum 41 | footer_privacy_policy: Datenschutzerklärung 42 | footer_content_license_prefix: > 43 | Inhalt lizensiert unter 44 | 45 | language_switch_no_tranlation_prefix: "Seite nicht übersetzt:" 46 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/en.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Edit page 3 | 4 | nav_navigation: Navigation 5 | nav_tags: Tags 6 | nav_more: More 7 | nav_top: Back to top 8 | 9 | form_placeholder_search: Search 10 | 11 | error_page_title: Lost? Don't worry 12 | error_message_title: Lost? 13 | error_message_code: Error 404 14 | error_message_text: > 15 | Seems like what you are looking for can't be found. Don't worry, we can 16 | bring you back to the homepage. 17 | 18 | button_toggle_dark: Toggle Dark/Light/Auto mode 19 | button_nav_open: Open Navigation 20 | button_nav_close: Close Navigation 21 | button_menu_open: Open Menu Bar 22 | button_menu_close: Close Menu Bar 23 | button_homepage: Back to homepage 24 | 25 | title_anchor_prefix: "Anchor to:" 26 | 27 | posts_read_more: Read full post 28 | posts_read_time: 29 | one: "One minute to read" 30 | other: "{{ . }} minutes to read" 31 | posts_update_prefix: Updated on 32 | posts_count: 33 | one: "One post" 34 | other: "{{ . }} posts" 35 | posts_tagged_with: All posts tagged with '{{ . }}' 36 | 37 | footer_build_with: > 38 | Built with Hugo and 39 | 40 | footer_legal_notice: Legal Notice 41 | footer_privacy_policy: Privacy Policy 42 | footer_content_license_prefix: > 43 | Content licensed under 44 | 45 | language_switch_no_tranlation_prefix: "Page not translated:" 46 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/images/readme.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/images/screenshot.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/images/tn.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head/meta" . }} 5 | {{ i18n "error_page_title" }} 6 | 7 | {{ partial "head/favicons" . }} 8 | {{ partial "head/others" . }} 9 | 10 | 11 | 12 | {{ partial "svg-icon-symbols" . }} 13 | 14 | 15 |
16 | 17 | 18 | {{ partial "site-header" (dict "Root" . "MenuEnabled" false) }} 19 | 20 | 21 |
22 |
23 |
24 | 25 |
26 |
27 |
{{ i18n "error_message_title" }}
28 |
{{ i18n "error_message_code" }}
29 |
30 | {{ i18n "error_message_text" .Site.BaseURL | safeHTML }} 31 |
32 |
33 |
34 |
35 | 36 | {{ partial "site-footer" . }} 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-heading.html: -------------------------------------------------------------------------------- 1 | {{- $showAnchor := (and (default true .Page.Params.GeekdocAnchor) (default true .Page.Site.Params.GeekdocAnchor)) -}} 2 | 3 | 4 | 5 | {{- if $showAnchor -}} 6 |
7 | 8 | {{ .Text | safeHTML }} 9 | 10 | 11 | 12 | 13 |
14 | {{- else -}} 15 |
16 | 17 | {{ .Text | safeHTML }} 18 | 19 |
20 | {{- end -}} 21 | 22 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-image.html: -------------------------------------------------------------------------------- 1 | {{ .Text }} 6 | {{- /* Drop trailing newlines */ -}} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-link.html: -------------------------------------------------------------------------------- 1 | {{- $raw := or (hasPrefix .Text " 12 | {{- .Text | safeHTML -}} 13 | 14 | {{- /* Drop trailing newlines */ -}} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head/meta" . }} 5 | 6 | {{- if eq .Kind "home" -}} 7 | {{ .Site.Title }} 8 | {{- else -}} 9 | {{ printf "%s | %s" (partial "utils/title" .) .Site.Title }} 10 | {{- end -}} 11 | 12 | 13 | {{ partial "head/favicons" . }} 14 | {{ partial "head/rel-me" . }} 15 | {{ partial "head/microformats" . }} 16 | {{ partial "head/others" . }} 17 | {{ partial "head/custom" . }} 18 | 19 | 20 | 21 | {{ partial "svg-icon-symbols" . }} 22 | 23 | 24 |
27 | 28 | 29 | {{ $navEnabled := default true .Page.Params.GeekdocNav }} 30 | {{ partial "site-header" (dict "Root" . "MenuEnabled" $navEnabled) }} 31 | 32 | 33 |
34 | {{ if $navEnabled }} 35 | 38 | {{ end }} 39 | 40 | 41 |
42 | {{ template "main" . }} 43 | 44 | 45 | 48 |
49 |
50 | 51 | {{ partial "site-footer" . }} 52 |
53 | 54 | {{ partial "foot" . }} 55 | 56 | 57 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 | 4 | 5 |
8 |

{{ partial "utils/title" . }}

9 | {{ partial "utils/content" . }} 10 |
11 | {{ end }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 | 4 | 5 |
8 |

{{ partial "utils/title" . }}

9 | {{ partial "utils/content" . }} 10 |
11 | {{ end }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/taxonomy.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages }} 3 | 33 | {{ end }} 34 | {{ end }} 35 | 36 | {{ define "post-tag" }} 37 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/terms.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages.ByTitle }} 3 |
4 |
5 |

6 | {{ partial "utils/title" . }} 7 |

8 |
9 | 10 |
11 | 12 | {{ $pageCount := len .Pages }} 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | {{ $latet := index .Pages.ByDate 0 }} 23 | {{ with $latet }} 24 | {{ partial "utils/title" . }} 25 | {{ end }} 26 | 27 | 28 |
29 |
30 | {{ end }} 31 | {{ end }} 32 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/foot.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.GeekdocSearch }} 2 | 3 | {{- $searchConfigFile := printf "search/%s.config.json" .Language.Lang -}} 4 | {{- $searchConfig := resources.Get "search/config.json" | resources.ExecuteAsTemplate $searchConfigFile . | resources.Minify -}} 5 | {{- $searchConfig.Publish -}} 6 | {{ end }} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/custom.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/favicons.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/meta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ hugo.Generator }} 6 | 7 | {{ $keywords := default .Site.Params.Keywords .Keywords }} 8 | 9 | {{- with partial "utils/description" . }} 10 | 11 | {{- end }} 12 | {{- with $keywords }} 13 | 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/microformats.html: -------------------------------------------------------------------------------- 1 | {{ partial "microformats/opengraph.html" . }} 2 | {{ partial "microformats/twitter_cards.html" . }} 3 | {{ partial "microformats/schema" . }} 4 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/others.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 17 | 18 | 23 | 28 | 29 | 34 | 39 | 40 | 45 | 50 | 51 | 56 | 61 | 62 | {{- with .OutputFormats.Get "html" }} 63 | {{ printf `` .Permalink .Rel .MediaType.Type | safeHTML }} 64 | {{- end }} 65 | 66 | {{- if (default false $.Site.Params.GeekdocOverwriteHTMLBase) }} 67 | 68 | {{- end }} 69 | 70 | {{ printf "" "Made with Geekdoc theme https://github.com/thegeeklab/hugo-geekdoc" | safeHTML }} 71 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/rel-me.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/language.html: -------------------------------------------------------------------------------- 1 | {{ if hugo.IsMultilingual }} 2 | 3 |
    4 |
  • 5 | {{ range .Site.Languages }} 6 | {{ if eq . $.Site.Language }} 7 | 8 | 9 | {{ .Lang | upper }} 10 | 11 | {{ end }} 12 | {{ end }} 13 | 14 | 15 | 48 |
  • 49 |
50 |
51 | {{ end }} 52 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu-bundle.html: -------------------------------------------------------------------------------- 1 | {{ $current := .current }} 2 | {{ template "menu-file" dict "sect" .source "current" $current "site" $current.Site }} 3 | 4 | 5 | 6 | {{ define "menu-file" }} 7 | {{ $current := .current }} 8 | {{ $site := .site }} 9 | 10 | 11 | 81 | {{ end }} 82 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu-extra.html: -------------------------------------------------------------------------------- 1 | {{ $current := .current }} 2 | {{ template "menu-extra" dict "sect" .source "current" $current "site" $current.Site "target" .target }} 3 | 4 | 5 | 6 | {{ define "menu-extra" }} 7 | {{ $current := .current }} 8 | {{ $site := .site }} 9 | {{ $target := .target }} 10 | {{ $sect := .sect }} 11 | 12 | {{ range sort (default (seq 0) $sect) "weight" }} 13 | {{ if isset . "ref" }} 14 | {{ $this := $site.GetPage .ref }} 15 | {{ $isCurrent := eq $current $this }} 16 | {{ $icon := default false .icon }} 17 | 18 | {{ $name := .name }} 19 | {{ if reflect.IsMap .name }} 20 | {{ $name = (index .name $site.Language.Lang) }} 21 | {{ end }} 22 | 23 | {{ if not .icon }} 24 | {{ errorf "Missing 'icon' attribute in data file for '%s' menu item '%s'" $target $name }} 25 | {{ end }} 26 | 27 | {{ if eq $target "header" }} 28 | 29 | 37 | 38 | {{ $name }} 39 | 40 | 41 | 42 | 43 | {{ end }} 44 | {{ end }} 45 | {{ end }} 46 | {{ end }} 47 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu-filetree.html: -------------------------------------------------------------------------------- 1 | {{ $current := . }} 2 | {{ template "tree-nav" dict "sect" .Site.Home.Sections "current" $current }} 3 | 4 | 5 | 6 | {{ define "tree-nav" }} 7 | {{ $current := .current }} 8 | 9 | 10 | 99 | {{ end }} 100 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu-nextprev.html: -------------------------------------------------------------------------------- 1 | {{ $current := . }} 2 | {{ $site := .Site }} 3 | {{ $current.Scratch.Set "prev" false }} 4 | {{ $current.Scratch.Set "getNext" false }} 5 | 6 | {{ $current.Scratch.Set "nextPage" false }} 7 | {{ $current.Scratch.Set "prevPage" false }} 8 | 9 | {{ template "menu_nextprev" dict "sect" $.Site.Data.menu.main.main "current" $current "site" $site }} 10 | 11 | {{ define "menu_nextprev" }} 12 | {{ $current := .current }} 13 | {{ $site := .site }} 14 | 15 | {{ range sort (default (seq 0) .sect) "weight" }} 16 | {{ $current.Scratch.Set "current" $current }} 17 | {{ $current.Scratch.Set "site" $site }} 18 | 19 | {{ $ref := default false .ref }} 20 | {{ if $ref }} 21 | {{ $site := $current.Scratch.Get "site" }} 22 | {{ $this := $site.GetPage .ref }} 23 | {{ $current := $current.Scratch.Get "current" }} 24 | 25 | {{ if reflect.IsMap .name }} 26 | {{ $current.Scratch.Set "refName" (index .name $site.Language.Lang) }} 27 | {{ else }} 28 | {{ $current.Scratch.Set "refName" .name }} 29 | {{ end }} 30 | {{ $name := $current.Scratch.Get "refName" }} 31 | 32 | {{ if $current.Scratch.Get "getNext" }} 33 | {{ $current.Scratch.Set "nextPage" (dict "name" $name "this" $this) }} 34 | {{ $current.Scratch.Set "getNext" false }} 35 | {{ end }} 36 | 37 | {{ if eq $current $this }} 38 | {{ $current.Scratch.Set "prevPage" ($current.Scratch.Get "prev") }} 39 | {{ $current.Scratch.Set "getNext" true }} 40 | {{ end }} 41 | 42 | {{ $current.Scratch.Set "prev" (dict "name" $name "this" $this) }} 43 | {{ end }} 44 | 45 | {{ $sub := default false .sub }} 46 | {{ if $sub }} 47 | {{ template "menu_nextprev" dict "sect" $sub "current" ($current.Scratch.Get "current") "site" ($current.Scratch.Get "site") }} 48 | {{ end }} 49 | {{ end }} 50 | {{ end }} 51 | 52 | {{ $showPrevNext := (and (default true .Site.Params.GeekdocNextPrev) .Site.Params.GeekdocMenuBundle) }} 53 | {{ if $showPrevNext }} 54 | 55 | {{ with ($current.Scratch.Get "prevPage") }} 56 | 61 | gdoc_arrow_left_alt 62 | {{ .name }} 63 | 64 | {{ end }} 65 | 66 | 67 | {{ with ($current.Scratch.Get "nextPage") }} 68 | 73 | {{ .name }} 74 | gdoc_arrow_right_alt 75 | 76 | {{ end }} 77 | 78 | {{ end }} 79 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu.html: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/opengraph.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | 3 | {{- if ne .Kind "home" }} 4 | 8 | {{- end }} 9 | {{- with .Site.Title }} 10 | 11 | {{- end }} 12 | {{- with partial "utils/featured" . }} 13 | 14 | {{- end }} 15 | {{- with partial "utils/description" . }} 16 | 17 | {{- end }} 18 | 19 | 20 | {{- with .Params.audio }} 21 | 22 | {{- end }} 23 | {{- with .Params.locale }} 24 | 25 | {{- end }} 26 | {{- with .Params.videos }} 27 | {{- range . }} 28 | 29 | {{- end }} 30 | {{- end }} 31 | 32 | {{- /* If it is part of a series, link to related articles */}} 33 | {{- if .Site.Taxonomies.series }} 34 | {{- $permalink := .Permalink -}} 35 | {{- $siteSeries := .Site.Taxonomies.series -}} 36 | {{- with .Params.series }} 37 | {{- range $name := . }} 38 | {{- $series := index $siteSeries ($name | urlize) }} 39 | {{- range $page := first 6 $series.Pages }} 40 | {{- if ne $page.Permalink $permalink }} 41 | 42 | {{- end }} 43 | {{- end }} 44 | {{- end }} 45 | {{- end }} 46 | {{- end }} 47 | 48 | {{ if $isPage -}} 49 | {{- $iso8601 := "2006-01-02T15:04:05-07:00" -}} 50 | 51 | {{- with .PublishDate }} 52 | 56 | {{- end }} 57 | {{- with .Lastmod }} 58 | 62 | {{- end }} 63 | {{- end }} 64 | 65 | {{- /* Facebook Page Admin ID for Domain Insights */}} 66 | {{- with .Site.Params.facebook.adminID }} 67 | 68 | {{- end }} 69 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/schema.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | {{- if eq .Kind "home" }} 3 | 21 | {{- else if $isPage }} 22 | 70 | {{- end }} 71 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/twitter_cards.html: -------------------------------------------------------------------------------- 1 | {{- with partial "utils/featured" . }} 2 | 3 | {{- else }} 4 | 5 | {{- end }} 6 | 7 | {{- with partial "utils/featured" . }} 8 | 9 | {{- end }} 10 | {{- with partial "utils/description" . }} 11 | 12 | {{- end }} 13 | {{- with .Site.Params.twitter -}} 14 | 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/page-header.html: -------------------------------------------------------------------------------- 1 | {{ $geekdocRepo := default (default false .Site.Params.GeekdocRepo) .Page.Params.GeekdocRepo }} 2 | {{ $geekdocEditPath := default (default false .Site.Params.GeekdocEditPath) .Page.Params.GeekdocEditPath }} 3 | {{ if .File }} 4 | {{ $.Scratch.Set "geekdocFilePath" (default (path.Join (default "content" .Site.Params.contentDir) .File.Path) .Page.Params.GeekdocFilePath) }} 5 | {{ else }} 6 | {{ $.Scratch.Set "geekdocFilePath" false }} 7 | {{ end }} 8 | 9 | {{ define "breadcrumb" }} 10 | {{ $parent := .page.Parent }} 11 | {{ if $parent }} 12 | {{ $name := (partial "utils/title" $parent) }} 13 | {{ $position := (sub .position 1) }} 14 | {{ $value := (printf "
  • %s
  • /
  • %s" $parent.RelPermalink $parent.RelPermalink $name $position .value) }} 15 | {{ template "breadcrumb" dict "page" $parent "value" $value "position" $position }} 16 | {{ else }} 17 | {{ .value | safeHTML }} 18 | {{ end }} 19 | {{ end }} 20 | 21 | {{ $showBreadcrumb := (and (default true .Page.Params.GeekdocBreadcrumb) (default true .Site.Params.GeekdocBreadcrumb)) }} 22 | {{ $showEdit := (and ($.Scratch.Get "geekdocFilePath") $geekdocRepo $geekdocEditPath) }} 23 |
    34 | {{ if $showBreadcrumb }} 35 |
    36 | 37 | 43 |
    44 | {{ end }} 45 | {{ if $showEdit }} 46 |
    47 | 48 | 49 | 52 | {{ i18n "edit_page" }} 53 | 54 | 55 |
    56 | {{ end }} 57 |
    58 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/posts/metadata.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {{ $tc := 0 }} 19 | {{ with .Params.tags }} 20 | {{ range sort . }} 21 | {{ $name := . }} 22 | {{ with $.Site.GetPage (printf "/tags/%s" $name | urlize) }} 23 | {{ if eq $tc 0 }} 24 | 25 | 26 | {{ template "post-tag" dict "name" $name "page" . }} 27 | 28 | {{ else }} 29 | 30 | {{ template "post-tag" dict "name" $name "page" . }} 31 | 32 | {{ end }} 33 | {{ end }} 34 | {{ $tc = (add $tc 1) }} 35 | {{ end }} 36 | {{ end }} 37 | 38 | {{ define "post-tag" }} 39 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/search.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.GeekdocSearch }} 2 | 17 | {{ end }} 18 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/site-footer.html: -------------------------------------------------------------------------------- 1 | 46 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/site-header.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{ if .MenuEnabled }} 4 | 14 | {{ end }} 15 |
    16 | 17 | 18 | 23 | {{ .Root.Site.Title }} 24 | 25 | 26 |
    27 |
    28 | 29 | {{ if .Root.Site.Data.menu.extra.header }} 30 | {{ partial "menu-extra" (dict "current" .Root "source" .Root.Site.Data.menu.extra.header "target" "header") }} 31 | {{ end }} 32 | 33 | 34 | 35 | 36 | {{ i18n "button_toggle_dark" }} 37 | 38 | 39 | 40 | {{ i18n "button_toggle_dark" }} 41 | 42 | 43 | 44 | {{ i18n "button_toggle_dark" }} 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {{ i18n "button_homepage" }} 53 | 54 | 55 | 56 | 57 | 58 | {{ partial "language" .Root }} 59 | 60 | 61 | 62 | 68 | 69 | 70 | 76 |
    77 |
    78 |
    79 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/svg-icon-symbols.html: -------------------------------------------------------------------------------- 1 | {{ range resources.Match "sprites/*.svg" }} 2 | {{ printf "" . | safeHTML }} 3 | {{ .Content | safeHTML }} 4 | {{ end }} 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/content.html: -------------------------------------------------------------------------------- 1 | {{ $content := .Content }} 2 | 3 | {{ $content = $content | replaceRE `` `` | safeHTML }} 4 | {{ $content = $content | replaceRE `((?:.|\n)+?
    )` `
    ${1}
    ` | safeHTML }} 5 | 6 | {{ return $content }} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/description.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | {{ $description := "" }} 3 | 4 | {{ if .Description }} 5 | {{ $description = .Description }} 6 | {{ else }} 7 | {{ if $isPage }} 8 | {{ $description = .Summary }} 9 | {{ else if .Site.Params.description }} 10 | {{ $description = .Site.Params.description }} 11 | {{ end }} 12 | {{ end }} 13 | 14 | {{ return $description }} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/featured.html: -------------------------------------------------------------------------------- 1 | {{ $img := "" }} 2 | 3 | {{ with $source := ($.Resources.ByType "image").GetMatch "{*feature*,*cover*,*thumbnail*}" }} 4 | {{ $featured := .Fill (printf "1200x630 %s" (default "Smart" .Params.anchor)) }} 5 | {{ $img = $featured.Permalink }} 6 | {{ else }} 7 | {{ with default $.Site.Params.images $.Params.images }} 8 | {{ $img = index . 0 | absURL }} 9 | {{ end }} 10 | {{ end }} 11 | 12 | {{ return $img }} 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/title.html: -------------------------------------------------------------------------------- 1 | {{ $title := "" }} 2 | 3 | {{ if .Title }} 4 | {{ $title = .Title }} 5 | {{ else if and .IsSection .File }} 6 | {{ $title = path.Base .File.Dir | humanize | title }} 7 | {{ else if and .IsPage .File }} 8 | {{ $title = .File.BaseFileName | humanize | title }} 9 | {{ end }} 10 | 11 | {{ return $title }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/posts/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages }} 3 | 31 | {{ end }} 32 | {{ end }} 33 | 34 | {{ define "post-tag" }} 35 | 46 | {{ end }} 47 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/posts/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
    3 |
    4 |

    {{ partial "utils/title" . }}

    5 | 8 |
    9 |
    10 | {{ partial "utils/content" . }} 11 |
    12 |
    13 | {{ end }} 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /tags/* 3 | 4 | Sitemap: {{ "sitemap.xml" | absURL }} 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/button.html: -------------------------------------------------------------------------------- 1 | {{ $ref := "" }} 2 | {{ $target := "" }} 3 | {{ $size := default "regular" (.Get "size" | lower) }} 4 | 5 | {{ if not (in (slice "regular" "large") $size) }} 6 | {{ $size = "regular" }} 7 | {{ end }} 8 | 9 | {{ with .Get "href" }} 10 | {{ $ref = . }} 11 | {{ $target = "_blank" }} 12 | {{ end }} 13 | 14 | {{ with .Get "relref" }} 15 | {{ $ref = relref $ . }} 16 | {{ end }} 17 | 18 | 19 | 20 | 25 | {{ $.Inner }} 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/columns.html: -------------------------------------------------------------------------------- 1 |
    2 | {{ range split .Inner "<--->" }} 3 |
    4 | {{ . | $.Page.RenderString }} 5 |
    6 | {{ end }} 7 |
    8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/expand.html: -------------------------------------------------------------------------------- 1 | {{ $id := substr (sha1 .Inner) 0 8 }} 2 |
    3 | 7 | 8 |
    9 | {{ .Inner | $.Page.RenderString }} 10 |
    11 |
    12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/hint.html: -------------------------------------------------------------------------------- 1 |
    2 | {{ .Inner | $.Page.RenderString }} 3 |
    4 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/icon.html: -------------------------------------------------------------------------------- 1 | {{ $id := .Get 0 }} 2 | 3 | {{- with $id -}} 4 | 5 | {{- end -}} 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/img.html: -------------------------------------------------------------------------------- 1 | {{ $source := ($.Page.Resources.ByType "image").GetMatch (printf "%s" (.Get "name")) }} 2 | {{ $customAlt := .Get "alt" }} 3 | {{ $customSize := .Get "size" }} 4 | {{ $lazyLoad := default (default true $.Site.Params.GeekdocImageLazyLoading) (.Get "lazy") }} 5 | 6 | {{ with $source }} 7 | {{ $caption := default .Title $customAlt }} 8 | 9 | {{ $tiny := (.Resize "320x").Permalink }} 10 | {{ $small := (.Resize "600x").Permalink }} 11 | {{ $medium := (.Resize "1200x").Permalink }} 12 | {{ $large := (.Resize "1800x").Permalink }} 13 | 14 | {{ $size := dict "tiny" $tiny "small" $small "medium" $medium "large" $large }} 15 | 16 | 17 |
    18 |
    19 | 20 | 21 | 28 | {{ $caption }} 35 | 36 | 37 | {{ with $caption -}} 38 |
    39 | {{ . }}{{ with $source.Params.credits }}({{ . | $.Page.RenderString }}){{ end }} 40 |
    41 | {{- end }} 42 |
    43 |
    44 | {{ end }} 45 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/include.html: -------------------------------------------------------------------------------- 1 | {{ $file := .Get "file" }} 2 | {{ $page := .Site.GetPage $file }} 3 | {{ $type := .Get "type" }} 4 | {{ $language := .Get "language" }} 5 | {{ $options :=.Get "options" }} 6 | 7 | 8 |
    9 | {{- if (.Get "language") -}} 10 | {{- highlight ($file | readFile) $language (default "linenos=table" $options) -}} 11 | {{- else if eq $type "html" -}} 12 | {{- $file | readFile | safeHTML -}} 13 | {{- else if eq $type "page" -}} 14 | {{- with $page }}{{ .Content }}{{ end -}} 15 | {{- else -}} 16 | {{- $file | readFile | $.Page.RenderString -}} 17 | {{- end -}} 18 |
    19 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/katex.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if not (.Page.Scratch.Get "katex") }} 3 | 4 | 8 | 9 | {{ .Page.Scratch.Set "katex" true }} 10 | {{ end }} 11 | 12 | 13 | 14 | {{ cond (in .Params "display") "\\[" "\\(" -}} 15 | {{- trim .Inner "\n" -}} 16 | {{- cond (in .Params "display") "\\]" "\\)" }} 17 | 18 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/mermaid.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if not (.Page.Scratch.Get "mermaid") }} 3 | 4 | 5 | {{ .Page.Scratch.Set "mermaid" true }} 6 | {{ end }} 7 | 8 | 9 |
    10 |   {{- .Inner -}}
    11 | 
    12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/tab.html: -------------------------------------------------------------------------------- 1 | {{ if .Parent }} 2 | {{ $name := .Get 0 }} 3 | {{ $group := printf "tabs-%s" (.Parent.Get 0) }} 4 | 5 | {{ if not (.Parent.Scratch.Get $group) }} 6 | {{ .Parent.Scratch.Set $group slice }} 7 | {{ end }} 8 | 9 | {{ .Parent.Scratch.Add $group (dict "Name" $name "Content" .Inner) }} 10 | {{ else }} 11 | {{ errorf "%q: 'tab' shortcode must be inside 'tabs' shortcode" .Page.Path }} 12 | {{ end }} 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/tabs.html: -------------------------------------------------------------------------------- 1 | {{ if .Inner }}{{ end }} 2 | {{ $id := .Get 0 }} 3 | {{ $group := printf "tabs-%s" $id }} 4 | 5 | 6 |
    7 | {{ range $index, $tab := .Scratch.Get $group }} 8 | 15 | 18 |
    19 | {{ .Content | $.Page.RenderString }} 20 |
    21 | {{ end }} 22 |
    23 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/toc-tree.html: -------------------------------------------------------------------------------- 1 | {{ $tocLevels := default (default 6 .Site.Params.GeekdocToC) .Page.Params.GeekdocToC }} 2 | 3 | {{ if $tocLevels }} 4 |
    5 | {{ template "toc-tree" dict "sect" .Page.Pages }} 6 |
    7 | {{ end }} 8 | 9 | 10 | 11 | {{ define "toc-tree" }} 12 | 41 | {{ end }} 42 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/toc.html: -------------------------------------------------------------------------------- 1 | {{ $tocLevels := default (default 6 .Site.Params.GeekdocToC) .Page.Params.GeekdocToC }} 2 | 3 | {{ if and $tocLevels .Page.TableOfContents }} 4 |
    5 | {{ .Page.TableOfContents }} 6 |
    7 |
    8 | {{ end }} 9 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/brand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 72 | 75 | 81 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/custom.css: -------------------------------------------------------------------------------- 1 | /* You can add custom styles here. */ -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-256x256.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-36x36.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-384x384.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-48x48.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-72x72.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/android-chrome-96x96.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-1024x1024.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-167x167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-167x167.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1125x2436.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1125x2436.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1136x640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1136x640.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2208.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2688.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2688.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1334x750.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1334x750.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1536x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1536x2048.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1620x2160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1620x2160.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2224.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2388.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2388.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1792x828.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1792x828.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x1536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x1536.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x2732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x2732.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2160x1620.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2160x1620.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2208x1242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2208x1242.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2224x1668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2224x1668.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2388x1668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2388x1668.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2436x1125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2436x1125.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2688x1242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2688x1242.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2732x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2732x2048.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-640x1136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-640x1136.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-750x1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-750x1334.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-828x1792.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-828x1792.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #2f333e 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/favicon-48x48.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 62 | 68 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/firefox_app_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/firefox_app_128x128.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/firefox_app_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/firefox_app_512x512.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/firefox_app_60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/firefox_app_60x60.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "geekdoc", 3 | "short_name": "geekdoc", 4 | "description": "Hugo theme made for documentation", 5 | "dir": "auto", 6 | "lang": "en-US", 7 | "display": "standalone", 8 | "orientation": "any", 9 | "start_url": "/?homescreen=1", 10 | "background_color": "#2f333e", 11 | "theme_color": "#2f333e", 12 | "icons": [ 13 | { 14 | "src": "android-chrome-36x36.png", 15 | "sizes": "36x36", 16 | "type": "image/png" 17 | }, 18 | { 19 | "src": "android-chrome-48x48.png", 20 | "sizes": "48x48", 21 | "type": "image/png" 22 | }, 23 | { 24 | "src": "android-chrome-72x72.png", 25 | "sizes": "72x72", 26 | "type": "image/png" 27 | }, 28 | { 29 | "src": "android-chrome-96x96.png", 30 | "sizes": "96x96", 31 | "type": "image/png" 32 | }, 33 | { 34 | "src": "android-chrome-144x144.png", 35 | "sizes": "144x144", 36 | "type": "image/png" 37 | }, 38 | { 39 | "src": "android-chrome-192x192.png", 40 | "sizes": "192x192", 41 | "type": "image/png" 42 | }, 43 | { 44 | "src": "android-chrome-256x256.png", 45 | "sizes": "256x256", 46 | "type": "image/png" 47 | }, 48 | { 49 | "src": "android-chrome-384x384.png", 50 | "sizes": "384x384", 51 | "type": "image/png" 52 | }, 53 | { 54 | "src": "android-chrome-512x512.png", 55 | "sizes": "512x512", 56 | "type": "image/png" 57 | } 58 | ] 59 | } -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/manifest.webapp: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "name": "geekdoc", 4 | "description": "Hugo theme made for documentation", 5 | "icons": { 6 | "60": "firefox_app_60x60.png", 7 | "128": "firefox_app_128x128.png", 8 | "512": "firefox_app_512x512.png" 9 | }, 10 | "developer": { 11 | "name": "Robert Kaussow", 12 | "url": null 13 | } 14 | } -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/mstile-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/mstile-310x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/mstile-310x310.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/favicon/mstile-70x70.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjNemo/underscore/fbf58eff4262ed0d1bce7fa548a8f01294f7d1e1/docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/273-3d271af5.chunk.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! For license information please see mermaid.esm.min.mjs.LICENSE.txt */ 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/katex-0ad34d3f.bundle.min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var t,e,o,n,r={4494:function(t,e,o){o(4093),document.addEventListener("DOMContentLoaded",(function(){o.e(116).then(o.t.bind(o,2116,23)).then((({default:t})=>{t(document.body)})).catch((t=>console.error(t)))}))},3491:function(t,e,o){t.exports=o.p+"fonts/KaTeX_AMS-Regular.woff"},5537:function(t,e,o){t.exports=o.p+"fonts/KaTeX_AMS-Regular.woff2"},282:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Caligraphic-Bold.woff"},4842:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Caligraphic-Bold.woff2"},1420:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Caligraphic-Regular.woff"},5148:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Caligraphic-Regular.woff2"},3873:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Fraktur-Bold.woff"},7925:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Fraktur-Bold.woff2"},7206:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Fraktur-Regular.woff"},1872:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Fraktur-Regular.woff2"},7888:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Bold.woff"},7823:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Bold.woff2"},6062:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-BoldItalic.woff"},8216:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-BoldItalic.woff2"},1411:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Italic.woff"},4968:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Italic.woff2"},9430:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Regular.woff"},556:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Main-Regular.woff2"},2379:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Math-BoldItalic.woff"},7312:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Math-BoldItalic.woff2"},8212:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Math-Italic.woff"},621:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Math-Italic.woff2"},3958:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Bold.woff"},8516:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Bold.woff2"},208:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Italic.woff"},9471:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Italic.woff2"},9229:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Regular.woff"},4671:function(t,e,o){t.exports=o.p+"fonts/KaTeX_SansSerif-Regular.woff2"},2629:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Script-Regular.woff"},9875:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Script-Regular.woff2"},8493:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size1-Regular.woff"},2986:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size1-Regular.woff2"},8398:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size2-Regular.woff"},4118:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size2-Regular.woff2"},498:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size3-Regular.woff"},8932:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size3-Regular.woff2"},8718:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size4-Regular.woff"},7633:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Size4-Regular.woff2"},2422:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Typewriter-Regular.woff"},4313:function(t,e,o){t.exports=o.p+"fonts/KaTeX_Typewriter-Regular.woff2"},4093:function(t,e,o){t.exports=o.p+"katex-e264b2b5.min.css"}},f={};function i(t){var e=f[t];if(void 0!==e)return e.exports;var o=f[t]={exports:{}};return r[t].call(o.exports,o,o.exports,i),o.exports}i.m=r,e=Object.getPrototypeOf?function(t){return Object.getPrototypeOf(t)}:function(t){return t.__proto__},i.t=function(o,n){if(1&n&&(o=this(o)),8&n)return o;if("object"==typeof o&&o){if(4&n&&o.__esModule)return o;if(16&n&&"function"==typeof o.then)return o}var r=Object.create(null);i.r(r);var f={};t=t||[null,e({}),e([]),e(e)];for(var a=2&n&&o;"object"==typeof a&&!~t.indexOf(a);a=e(a))Object.getOwnPropertyNames(a).forEach((function(t){f[t]=function(){return o[t]}}));return f.default=function(){return o},i.d(r,f),r},i.d=function(t,e){for(var o in e)i.o(e,o)&&!i.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},i.f={},i.e=function(t){return Promise.all(Object.keys(i.f).reduce((function(e,o){return i.f[o](t,e),e}),[]))},i.u=function(t){return"js/"+t+"-d8286ca2.chunk.min.js"},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o={},n="geekdoc:",i.l=function(t,e,r,f){if(o[t])o[t].push(e);else{var a,u;if(void 0!==r)for(var c=document.getElementsByTagName("script"),s=0;sr.length(this._area)&&(i--,n--)}return e||this},keys:function(t){return this.each((function(t,e,n){n.push(t)}),t||[])},get:function(t,e){var n,i=r.get(this._area,this._in(t));return"function"==typeof e&&(n=e,e=null),null!==i?r.parse(i,n):null!=e?e:i},getAll:function(t){return this.each((function(t,e,n){n[t]=e}),t||{})},transact:function(t,e,n){var r=this.get(t,n),i=e(r);return this.set(t,void 0===i?r:i),this},set:function(t,e,n){var i,o=this.get(t);return null!=o&&!1===n?e:("boolean"!=typeof n&&(i=n),r.set(this._area,this._in(t),r.stringify(e,i))||o)},setAll:function(t,e){var n,r;for(var i in t)r=t[i],this.set(i,r,e)!==r&&(n=!0);return n},add:function(t,e,n){var i=this.get(t);if(i instanceof Array)e=i.concat(e);else if(null!==i){var o=typeof i;if(o===typeof e&&"object"===o){for(var a in e)i[a]=e[a];e=i}else e=i+e}return r.set(this._area,this._in(t),r.stringify(e,n)),e},remove:function(t,e){var n=this.get(t,e);return r.remove(this._area,this._in(t)),n},clear:function(){return this._ns?this.each((function(t){r.remove(this._area,this._in(t))}),1):r.clear(this._area),this},clearAll:function(){var t=this._area;for(var e in r.areas)r.areas.hasOwnProperty(e)&&(this._area=r.areas[e],this.clear());return this._area=t,this},_in:function(t){return"string"!=typeof t&&(t=r.stringify(t)),this._ns?this._ns+t:t},_out:function(t){return this._ns?t&&0===t.indexOf(this._ns)?t.substring(this._ns.length):void 0:t}},storage:function(t){return r.inherit(r.storageAPI,{items:{},name:t})},storageAPI:{length:0,has:function(t){return this.items.hasOwnProperty(t)},key:function(t){var e=0;for(var n in this.items)if(this.has(n)&&t===e++)return n},setItem:function(t,e){this.has(t)||this.length++,this.items[t]=e},removeItem:function(t){this.has(t)&&(delete this.items[t],this.length--)},getItem:function(t){return this.has(t)?this.items[t]:null},clear:function(){for(var t in this.items)this.removeItem(t)}}},i=r.Store("local",function(){try{return localStorage}catch(t){}}());i.local=i,i._=r,i.area("session",function(){try{return sessionStorage}catch(t){}}()),i.area("page",r.storage("page")),"function"==typeof n&&void 0!==n.amd?n("store2",[],(function(){return i})):t.exports?t.exports=i:(e.store&&(r.conflict=e.store),e.store=i)}(this,this&&this.define)},6914:function(t,e,n){"use strict";n.r(e),n.d(e,{AUTO_MODE:function(){return o},DARK_MODE:function(){return r},LIGHT_MODE:function(){return i},THEME:function(){return a},TOGGLE_MODES:function(){return s}});const r="dark",i="light",o="auto",a="hugo-geekdoc",s=[o,r,i]}},r={};function i(t){var e=r[t];if(void 0!==e)return e.exports;var o=r[t]={exports:{}};return n[t].call(o.exports,o,o.exports,i),o.exports}i.m=n,i.d=function(t,e){for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.f={},i.e=function(t){return Promise.all(Object.keys(i.f).reduce((function(e,n){return i.f[n](t,e),e}),[]))},i.u=function(t){return"js/"+t+"-3d271af5.chunk.min.js"},i.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(t){if("object"==typeof window)return window}}(),i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},t={},e="geekdoc:",i.l=function(n,r,o,a){if(t[n])t[n].push(r);else{var s,u;if(void 0!==o)for(var c=document.getElementsByTagName("script"),h=0;h{t.initialize({flowchart:{useMaxWidth:!0},theme:"base",themeVariables:{darkMode:c,primaryColor:u}})})).catch((t=>console.error(t)))}))}()}(); -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/search-1c4cfb2d.bundle.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /**! 2 | * FlexSearch.js v0.7.21 (Compact) 3 | * Copyright 2018-2021 Nextapps GmbH 4 | * Author: Thomas Wilkerling 5 | * Licence: Apache-2.0 6 | * https://github.com/nextapps-de/flexsearch 7 | */ 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/mobile-1d04b92f.min.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width: 39rem){.gdoc-nav{margin-left:-16rem;font-size:16px}.gdoc-nav__control{display:inline-block}.gdoc-header .icon{width:1.5rem;height:1.5rem}.gdoc-brand{font-size:1.5rem;line-height:1.5rem}.gdoc-brand__img{display:none}.gdoc-menu-header__items{display:none}.gdoc-menu-header__control,.gdoc-menu-header__home{display:flex}.gdoc-error{padding:6rem 1rem}.gdoc-error .icon{width:6rem;height:6rem}.gdoc-error__message{padding-left:2rem}.gdoc-error__line{padding:.25rem 0}.gdoc-error__title{font-size:2rem}.gdoc-page__header .breadcrumb,.hidden-mobile{display:none}.flex-mobile-column{flex-direction:column}#menu-control:checked~main .gdoc-nav nav,#menu-control:checked~main .gdoc-page{transform:translateX(16rem)}#menu-control:checked~main .gdoc-page{opacity:.25}#menu-control:checked~.gdoc-header .gdoc-nav__control .icon.gdoc_menu{display:none}#menu-control:checked~.gdoc-header .gdoc-nav__control .icon.gdoc_arrow_back{display:inline-block}#menu-header-control:checked~.gdoc-header .gdoc-brand{display:none}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__items{display:flex}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__control .icon.gdoc_keyboard_arrow_left{display:none}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/print-19966b38.min.css: -------------------------------------------------------------------------------- 1 | @media print{.gdoc-nav,.gdoc-footer .container span:not(:first-child),.editpage{display:none}.gdoc-footer{border-top:1px solid #dee2e6}.gdoc-markdown pre{white-space:pre-wrap;overflow-wrap:break-word}.chroma code{border:1px solid #dee2e6;padding:.5rem !important;font-weight:normal !important}.gdoc-markdown code{font-weight:bold}a,a:visited{color:inherit !important;text-decoration:none !important}.gdoc-toc{flex:none}.gdoc-toc nav{position:relative;width:auto}.wrapper{display:block}.wrapper main{display:block}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Geekdoc" 2 | license = "MIT" 3 | licenselink = "https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE" 4 | description = "Hugo theme made for documentation" 5 | homepage = "https://geekdocs.de/" 6 | demosite = "https://geekdocs.de/" 7 | tags = ["docs", "documentation", "responsive", "simple"] 8 | min_version = "0.83.0" 9 | 10 | [author] 11 | name = "Robert Kaussow" 12 | homepage = "https://thegeeklab.de/" 13 | -------------------------------------------------------------------------------- /drop.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Drop returns the rest of the elements in a slice. 4 | // Pass an index to return the values of the slice from that index onward. 5 | func Drop[T any](values []T, index int) (rest []T) { 6 | for i, value := range values { 7 | if i != index { 8 | rest = append(rest, value) 9 | } 10 | } 11 | return rest 12 | } 13 | -------------------------------------------------------------------------------- /drop_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestDrop(t *testing.T) { 12 | 13 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 14 | want := []int{1, 9, 2, 3, 7, 4, 6, 5} 15 | 16 | assert.Equal(t, want, u.Drop(nums, 3)) 17 | } 18 | -------------------------------------------------------------------------------- /each.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Each iterates over a slice of elements, yielding each in turn to an action function. 4 | // Returns the slice for piping. 5 | func Each[T any](values []T, action func(T)) []T { 6 | for _, v := range values { 7 | action(v) 8 | } 9 | return values 10 | } 11 | -------------------------------------------------------------------------------- /each_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/rjNemo/underscore" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestEach(t *testing.T) { 13 | names := []string{"Alice", "Bob", "Charles"} 14 | want := []string{"Hi Alice", "Hi Bob", "Hi Charles"} 15 | 16 | res := make([]string, 0) 17 | underscore.Each(names, func(n string) { 18 | res = append(res, fmt.Sprintf("Hi %s", n)) 19 | }) 20 | 21 | assert.Equal(t, want, res) 22 | } 23 | 24 | func TestEachReturnsInitialSlice(t *testing.T) { 25 | names := []string{"Alice", "Bob", "Charles"} 26 | want := []string{"Alice", "Bob", "Charles"} 27 | 28 | res := make([]string, 0) 29 | 30 | assert.Equal(t, want, underscore.Each(names, func(n string) { 31 | res = append(res, fmt.Sprintf("Hi %s", n)) 32 | })) 33 | } 34 | -------------------------------------------------------------------------------- /examples/filterMapReduce.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | u "github.com/rjNemo/underscore" 5 | ) 6 | 7 | func filterMapReduce() int { 8 | numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 9 | // filter even numbers from the slice 10 | evens := u.Filter(numbers, func(n int) bool { return n%2 == 0 }) 11 | // square every number in the slice 12 | squares := u.Map(evens, func(n int) int { return n * n }) 13 | // reduce the slice to its sum 14 | res := u.Reduce(squares, func(n, acc int) int { return n + acc }, 0) 15 | 16 | return res 17 | } 18 | -------------------------------------------------------------------------------- /examples/filterMapReduce_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestFilterMapReduceExample(t *testing.T) { 10 | assert.Equal(t, 120, filterMapReduce()) 11 | } 12 | -------------------------------------------------------------------------------- /examples/pipe.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | u "github.com/rjNemo/underscore" 5 | ) 6 | 7 | func piping() int { 8 | return u.NewPipe([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). 9 | // filter even numbers from the slice 10 | Filter(func(n int) bool { return n%2 == 0 }). 11 | // square every number in the slice 12 | Map(func(n int) int { return n * n }). 13 | // reduce the slice to its sum 14 | Reduce(func(n, acc int) int { return n + acc }, 0) 15 | } 16 | -------------------------------------------------------------------------------- /examples/pipe_test.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestPipingExample(t *testing.T) { 10 | assert.Equal(t, 120, piping()) 11 | } 12 | -------------------------------------------------------------------------------- /filter.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate). 4 | func Filter[T any](values []T, predicate func(T) bool) (res []T) { 5 | for _, v := range values { 6 | if predicate(v) { 7 | res = append(res, v) 8 | } 9 | } 10 | return res 11 | } 12 | -------------------------------------------------------------------------------- /filter_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestFilter(t *testing.T) { 12 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 13 | isEven := func(n int) bool { return n%2 == 0 } 14 | 15 | want := []int{0, 2, 4, 6, 8} 16 | assert.Equal(t, want, u.Filter(nums, isEven)) 17 | } 18 | -------------------------------------------------------------------------------- /find.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import "errors" 4 | 5 | // Find looks through each value in the slice, returning the first one that passes a truth test (predicate), 6 | // or the default value for the type and an error if no value passes the test. 7 | // The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice. 8 | func Find[T any](values []T, predicate func(T) bool) (res T, err error) { 9 | for _, v := range values { 10 | if predicate(v) { 11 | return v, nil 12 | } 13 | } 14 | return res, errors.New("value not found") 15 | } 16 | -------------------------------------------------------------------------------- /find_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestFind(t *testing.T) { 11 | want := 5 12 | nums := []int{2, 4, 5, 6, 8, 0} 13 | isOdd := func(n int) bool { return n%2 != 0 } 14 | 15 | got, err := u.Find(nums, isOdd) 16 | assert.Equal(t, want, got) 17 | assert.NoError(t, err) 18 | } 19 | 20 | func TestNotFound(t *testing.T) { 21 | nums := []int{2, 4, 6, 8, 0} 22 | isOdd := func(n int) bool { return n%2 != 0 } 23 | 24 | _, err := u.Find(nums, isOdd) 25 | assert.Error(t, err) 26 | } 27 | -------------------------------------------------------------------------------- /flatmap.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Flatmap flatten the input slice element into the new slice. FlatMap maps every element with the help of a mapper function, then flattens the input slice element into the new slice. 4 | func Flatmap[T any](values []T, mapper func(n T) []T) []T { 5 | res := make([]T, 0) 6 | for _, v := range values { 7 | vs := mapper(v) 8 | res = append(res, vs...) 9 | } 10 | return res 11 | } 12 | -------------------------------------------------------------------------------- /flatmap_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestFlatmap(t *testing.T) { 11 | nums := []int{1, 2, 3, 4} 12 | transform := func(n int) []int { return []int{(n - 1) * n, (n) * n} } 13 | want := []int{0, 1, 2, 4, 6, 9, 12, 16} 14 | 15 | assert.Equal(t, want, u.Flatmap(nums, transform)) 16 | } 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rjNemo/underscore 2 | 3 | go 1.23.3 4 | 5 | require ( 6 | github.com/stretchr/testify v1.8.4 7 | golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.1 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 6 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 7 | golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk= 8 | golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 11 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 12 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 13 | -------------------------------------------------------------------------------- /groupby.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // GroupBy splits a slice into a map[K][]V grouped by the result of the iterator function. 4 | func GroupBy[K comparable, V any](values []V, f func(V) K) map[K][]V { 5 | res := make(map[K][]V, 0) 6 | for _, v := range values { 7 | k := f(v) 8 | if r, ok := res[k]; ok { 9 | res[k] = append(r, v) 10 | } else { 11 | res[k] = []V{v} 12 | } 13 | } 14 | return res 15 | } 16 | -------------------------------------------------------------------------------- /groupby_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | 9 | u "github.com/rjNemo/underscore" 10 | ) 11 | 12 | func TestGroupBy(t *testing.T) { 13 | nums := []float64{1.3, 2.1, 2.4} 14 | want := map[int][]float64{ 15 | 1: {1.3}, 16 | 2: {2.1, 2.4}, 17 | } 18 | f := func(n float64) int { 19 | return int(math.Floor(n)) 20 | } 21 | assert.Equal(t, want, u.GroupBy(nums, f)) 22 | } 23 | -------------------------------------------------------------------------------- /intersection.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Intersection computes the list of values that are the intersection of all the slices. 4 | // Each value in the result is present in each of the slices. 5 | func Intersection[T comparable](a, b []T) (res []T) { 6 | for _, n := range a { 7 | if Contains(b, n) { 8 | res = append(res, n) 9 | } 10 | } 11 | return res 12 | } 13 | -------------------------------------------------------------------------------- /intersection_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestIntersection(t *testing.T) { 12 | a := []int{1, 3, 5, 7, 9} 13 | b := []int{2, 3, 5, 8, 0} 14 | want := []int{3, 5} 15 | 16 | assert.Equal(t, want, u.Intersection(a, b)) 17 | } 18 | -------------------------------------------------------------------------------- /join.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Join joins two slices together and returns a Tuple of [T, []P], the selectors allow you to pick the 4 | // keys you want to use from your struct's to join the sets together 5 | func Join[T, P any, S comparable]( 6 | left []T, 7 | right []P, 8 | leftSelector func(T) S, 9 | rightSelector func(P) S) []Tuple[T, []P] { 10 | 11 | var results = make([]Tuple[T, []P], 0, len(left)) 12 | for _, l := range left { 13 | var matches = Filter(right, func(r P) bool { return leftSelector(l) == rightSelector(r) }) 14 | var tuple = Tuple[T, []P]{Left: l, Right: matches} 15 | results = append(results, tuple) 16 | } 17 | 18 | return results 19 | } 20 | 21 | // JoinProject joins two slices together and returns a []O where O is defined by the output 22 | // of your projection function 23 | // The selectors allow you to pick the keys from your structure to use as the join keys 24 | // While the projection functions allows you to reformat joined datasets 25 | // (Tuple of [T, []P]) into your own struct or type 26 | func JoinProject[L, R, O any, S comparable]( 27 | left []L, 28 | right []R, 29 | leftSelector func(L) S, 30 | rightSelector func(R) S, 31 | projection func(Tuple[L, []R]) O) (results []O) { 32 | 33 | for _, x := range Join(left, right, leftSelector, rightSelector) { 34 | results = append(results, projection(x)) 35 | } 36 | 37 | return results 38 | } 39 | -------------------------------------------------------------------------------- /join_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var zero = u.Tuple[int, string]{Left: 0, Right: "Zero"} 11 | var one = u.Tuple[int, string]{Left: 1, Right: "One"} 12 | var two = u.Tuple[int, string]{Left: 2, Right: "Two"} 13 | var three = u.Tuple[int, string]{Left: 3, Right: "Three"} 14 | 15 | func Test_Join_Can_Join_Two_Slices_Together(t *testing.T) { 16 | var left = []u.Tuple[int, string]{zero, one, two, three} 17 | var right = []u.Tuple[int, string]{one, three, two, three, two, three} 18 | 19 | selector := func(x u.Tuple[int, string]) int { return x.Left } 20 | 21 | var joined = u.Join(left, right, selector, selector) 22 | var want = []u.Tuple[u.Tuple[int, string], []u.Tuple[int, string]]{ 23 | {Left: zero, Right: nil}, 24 | {Left: one, Right: []u.Tuple[int, string]{one}}, 25 | {Left: two, Right: []u.Tuple[int, string]{two, two}}, 26 | {Left: three, Right: []u.Tuple[int, string]{three, three, three}}, 27 | } 28 | 29 | assert.Equal(t, want, joined) 30 | } 31 | 32 | func Test_Join_Can_Join_and_Project_Two_Slices_Together(t *testing.T) { 33 | var left = []u.Tuple[int, string]{zero, one, two, three} 34 | var right = []u.Tuple[int, string]{one, three, two, three, two, three} 35 | 36 | selector := func(x u.Tuple[int, string]) int { return x.Left } 37 | project := func(x u.Tuple[u.Tuple[int, string], []u.Tuple[int, string]]) int { 38 | return len(x.Right) // projecting to a could of how many 39 | } 40 | 41 | var joined = u.JoinProject(left, right, selector, selector, project) 42 | var want = []int{0, 1, 2, 3} 43 | 44 | assert.Equal(t, want, joined) 45 | } 46 | -------------------------------------------------------------------------------- /last.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Last returns the last element of the slice 4 | func Last[T any](values []T) T { 5 | n := len(values) 6 | return values[n-1] 7 | } 8 | -------------------------------------------------------------------------------- /last_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestLast(t *testing.T) { 12 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 13 | want := 5 14 | assert.Equal(t, want, u.Last(nums)) 15 | } 16 | -------------------------------------------------------------------------------- /map.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Map produces a new slice of values by mapping each value in the slice through 4 | // a transform function. 5 | func Map[T, P any](values []T, transform func(T) P) []P { 6 | res := make([]P, 0, len(values)) 7 | for _, v := range values { 8 | res = append(res, transform(v)) 9 | } 10 | return res 11 | } 12 | -------------------------------------------------------------------------------- /map_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestMap(t *testing.T) { 12 | nums := []int{1, 2, 3} 13 | f := func(n int) int { 14 | return n * n 15 | } 16 | want := []int{1, 4, 9} 17 | assert.Equal(t, want, u.Map(nums, f)) 18 | } 19 | -------------------------------------------------------------------------------- /maps/map.go: -------------------------------------------------------------------------------- 1 | package maps 2 | 3 | type M[K comparable, V any] map[K]V 4 | 5 | // Map produces a new slice of values by mapping each value in the slice through 6 | // a transform function. 7 | func Map[K, Q comparable, V, W any](m M[K, V], f func(K, V) M[Q, W]) M[Q, W] { 8 | res := make(M[Q, W], len(m)) 9 | for k, v := range m { 10 | mm := f(k, v) 11 | for k2, v2 := range mm { 12 | res[k2] = v2 13 | } 14 | } 15 | return res 16 | } 17 | -------------------------------------------------------------------------------- /maps/map_test.go: -------------------------------------------------------------------------------- 1 | package maps_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | m "github.com/rjNemo/underscore/maps" 10 | ) 11 | 12 | func TestMap(t *testing.T) { 13 | scores := m.M[string, int]{ 14 | "alice": 0, 15 | "bob": 10, 16 | "clara": 7, 17 | "david": 23, 18 | } 19 | 20 | hasWon := func(key string, value int) m.M[string, bool] { return m.M[string, bool]{key: value > 21} } 21 | want := m.M[string, bool]{ 22 | "alice": false, 23 | "bob": false, 24 | "clara": false, 25 | "david": true} 26 | assert.Equal(t, want, m.Map(scores, hasWon)) 27 | } 28 | 29 | func TestMapSlices(t *testing.T) { 30 | scores := []m.M[string, int]{ 31 | {"score": 0}, 32 | {"score": 10}, 33 | {"score": 7}, 34 | {"score": 23}, 35 | } 36 | 37 | hasWon := func(s m.M[string, int]) bool { return s["score"] > 21 } 38 | want := []bool{false, false, false, true} 39 | assert.Equal(t, want, u.Map(scores, hasWon)) 40 | } 41 | -------------------------------------------------------------------------------- /max.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import "golang.org/x/exp/constraints" 4 | 5 | // Max returns the maximum value in the slice. 6 | // This function can currently only compare numbers reliably. 7 | // This function uses operator <. 8 | func Max[T constraints.Ordered](values []T) T { 9 | max := values[0] 10 | for _, v := range values { 11 | if v > max { 12 | max = v 13 | } 14 | } 15 | return max 16 | } 17 | -------------------------------------------------------------------------------- /max_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestMax(t *testing.T) { 12 | nums := []int{1, 9, 2, 8, 3, 7, 4, 6, 5} 13 | want := 9 14 | assert.Equal(t, want, u.Max(nums)) 15 | } 16 | -------------------------------------------------------------------------------- /min.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import "golang.org/x/exp/constraints" 4 | 5 | // Min returns the minimum value in the slice. 6 | // This function can currently only compare numbers reliably. 7 | // This function uses operator <. 8 | func Min[T constraints.Ordered](values []T) T { 9 | min := values[0] 10 | for _, v := range values { 11 | if v < min { 12 | min = v 13 | } 14 | } 15 | return min 16 | } 17 | -------------------------------------------------------------------------------- /min_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestMin(t *testing.T) { 12 | nums := []int{9, 2, 1, 8, 3, 7, 4, 6, 5} 13 | want := 1 14 | assert.Equal(t, want, u.Min(nums)) 15 | } 16 | -------------------------------------------------------------------------------- /orderBy.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // OrderBy orders a slice by a field value within a struct, the predicate allows you 4 | // to pick the fields you want to orderBy. Use > for ASC or < for DESC 5 | // 6 | // func (left Person, right Person) bool { return left.Age > right.Age } 7 | func OrderBy[T any](list []T, predicate func(T, T) bool) []T { 8 | swaps := true 9 | var tmp T 10 | 11 | //todo: replace with a faster algorithm, this one is pretty simple 12 | for swaps { 13 | swaps = false 14 | 15 | for i := 0; i < len(list)-1; i++ { 16 | if predicate(list[i], list[i+1]) { 17 | swaps = true 18 | tmp = list[i] 19 | 20 | list[i] = list[i+1] 21 | list[i+1] = tmp 22 | } 23 | } 24 | } 25 | 26 | return list 27 | } 28 | -------------------------------------------------------------------------------- /orderBy_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func Test_OrderBy_Asc(t *testing.T) { 12 | set := u.Range(5, 0) 13 | want := u.Range(0, 5) 14 | 15 | result := u.OrderBy(set, func(left int, right int) bool { 16 | return left > right 17 | }) 18 | 19 | assert.Equal(t, want, result) 20 | } 21 | 22 | func Test_OrderBy_Desc(t *testing.T) { 23 | set := u.Range(0, 5) 24 | want := u.Range(5, 0) 25 | 26 | result := u.OrderBy(set, func(left int, right int) bool { 27 | return left < right 28 | }) 29 | 30 | assert.Equal(t, want, result) 31 | } 32 | -------------------------------------------------------------------------------- /partition.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Partition splits the slice into two slices: one whose elements all satisfy predicate 4 | // and one whose elements all do not satisfy predicate. 5 | func Partition[T any](values []T, predicate func(T) bool) ([]T, []T) { 6 | keep := make([]T, 0) 7 | reject := make([]T, 0) 8 | 9 | for _, v := range values { 10 | if predicate(v) { 11 | keep = append(keep, v) 12 | } else { 13 | reject = append(reject, v) 14 | } 15 | } 16 | return keep, reject 17 | } 18 | -------------------------------------------------------------------------------- /partition_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestPartition(t *testing.T) { 12 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 13 | isEven := func(n int) bool { return n%2 == 0 } 14 | 15 | wantEvens := []int{0, 2, 4, 6, 8} 16 | wantOdds := []int{1, 3, 5, 7, 9} 17 | 18 | evens, odds := u.Partition(nums, isEven) 19 | 20 | assert.Equal(t, wantEvens, evens) 21 | assert.Equal(t, wantOdds, odds) 22 | } 23 | -------------------------------------------------------------------------------- /pipe.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import ( 4 | "golang.org/x/exp/constraints" 5 | ) 6 | 7 | type Pipe[T constraints.Ordered] struct { 8 | Value []T 9 | } 10 | 11 | // NewPipe starts a Pipe. All future method calls will return Pipe structs. When you've finished the computation, 12 | // call Value to retrieve the final value. 13 | // 14 | // Methods not returning a slice such as Reduce, All, Any, will break the Pipe and return Value instantly. 15 | func NewPipe[T constraints.Ordered](value []T) Pipe[T] { 16 | return Pipe[T]{Value: value} 17 | } 18 | 19 | // All returns true if all the values in the slice pass the predicate truth test. 20 | // Short-circuits and stops traversing the slice if a false element is found. 21 | // Breaks the Pipe. 22 | func (c Pipe[T]) All(predicate func(T) bool) bool { 23 | return All(c.Value, predicate) 24 | } 25 | 26 | // Any returns true if any of the values in the slice pass the predicate truth test. 27 | // Short-circuits and stops traversing the slice if a true element is found. 28 | // Breaks the Pipe. 29 | func (c Pipe[T]) Any(predicate func(T) bool) bool { 30 | return Any(c.Value, predicate) 31 | } 32 | 33 | // Contains returns true if the value is present in the slice and breaks the Pipe. 34 | func (c Pipe[T]) Contains(value T) bool { 35 | return Contains(c.Value, value) 36 | } 37 | 38 | // Each iterates over a slice of elements, yielding each in turn to an action function. 39 | // Breaks the Pipe. 40 | func (c Pipe[T]) Each(action func(T)) { 41 | Each(c.Value, action) 42 | } 43 | 44 | // Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate). 45 | func (c Pipe[T]) Filter(predicate func(n T) bool) Pipe[T] { 46 | return Pipe[T]{Value: Filter(c.Value, predicate)} 47 | } 48 | 49 | // Find looks through each value in the slice, returning the first one that passes a truth test (predicate), 50 | // or the default value for the type and an error if no value passes the test. 51 | // The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice. 52 | // Breaks the Pipe. 53 | func (c Pipe[T]) Find(predicate func(n T) bool) (T, error) { 54 | return Find(c.Value, predicate) 55 | } 56 | 57 | // Map produces a new slice of values by mapping each value in the slice through 58 | // a transform function. 59 | // 60 | // TODO: Move from T to P. 61 | func (c Pipe[T]) Map(transform func(n T) T) Pipe[T] { 62 | return Pipe[T]{Value: Map(c.Value, transform)} 63 | } 64 | 65 | // Max returns the maximum value in the slice. 66 | // This function can currently only compare numbers reliably. 67 | // This function uses operator <. 68 | // Breaks the Pipe. 69 | func (c Pipe[T]) Max() T { 70 | return Max(c.Value) 71 | } 72 | 73 | // Min returns the minimum value in the slice. 74 | // This function can currently only compare numbers reliably. 75 | // This function uses operator <. 76 | // Breaks the Pipe. 77 | func (c Pipe[T]) Min() T { 78 | return Min(c.Value) 79 | } 80 | 81 | // Partition splits the slice into two slices: one whose elements all satisfy predicate 82 | // and one whose elements all do not satisfy predicate. 83 | // Breaks the Pipe. 84 | func (c Pipe[T]) Partition(predicate func(T) bool) ([]T, []T) { 85 | return Partition(c.Value, predicate) 86 | } 87 | 88 | // Reduce combine a list of values into a single value and breaks the Pipe. 89 | // acc is the initial state, and each successive step of it should be returned by the reduction function. 90 | func (c Pipe[T]) Reduce(reducer func(n, acc T) T, acc T) T { 91 | return Reduce(c.Value, reducer, acc) 92 | } 93 | -------------------------------------------------------------------------------- /pipe_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestChainFilter(t *testing.T) { 12 | want := []int{2, 4, 6, 8} 13 | assert.Equal(t, 14 | want, 15 | u.NewPipe(nums).Filter(isEven).Value, 16 | ) 17 | } 18 | 19 | func TestChainFilterMap(t *testing.T) { 20 | want := []int{4, 16, 36, 64} 21 | assert.Equal(t, 22 | want, 23 | u.NewPipe(nums). 24 | Filter(isEven). 25 | Map(toSquare). 26 | Value) 27 | } 28 | 29 | func TestChainFilterMapReduce(t *testing.T) { 30 | want := 120 31 | assert.Equal(t, 32 | want, 33 | u.NewPipe(nums). 34 | Filter(isEven). 35 | Map(toSquare). 36 | Reduce(sum, 0)) 37 | } 38 | 39 | func TestChainFilterMapContains(t *testing.T) { 40 | assert.True(t, u.NewPipe(nums). 41 | Filter(isEven). 42 | Map(toSquare). 43 | Contains(16)) 44 | } 45 | 46 | func TestChainFilterMapEach(t *testing.T) { 47 | want := []int{5, 17, 37, 65} 48 | res := make([]int, 0) 49 | u.NewPipe(nums). 50 | Filter(isEven). 51 | Map(toSquare). 52 | Each(func(n int) { res = append(res, n+1) }) 53 | assert.Equal(t, want, res) 54 | } 55 | 56 | func TestChainFilterMapAll(t *testing.T) { 57 | assert.True(t, u.NewPipe(nums). 58 | Filter(isEven). 59 | Map(toSquare). 60 | All(func(n int) bool { return n%4 == 0 })) 61 | } 62 | 63 | func TestChainFilterMapFind(t *testing.T) { 64 | n, err := u.NewPipe(nums). 65 | Filter(isEven). 66 | Map(toSquare). 67 | Find(func(n int) bool { return n%4 == 0 }) 68 | assert.Equal(t, 4, n) 69 | assert.NoError(t, err) 70 | } 71 | 72 | func TestChainFilterMapMax(t *testing.T) { 73 | want := 64 74 | assert.Equal(t, want, u.NewPipe(nums). 75 | Filter(isEven). 76 | Map(toSquare). 77 | Max()) 78 | } 79 | 80 | func TestChainFilterMapMin(t *testing.T) { 81 | w := 4 82 | assert.Equal(t, w, u.NewPipe(nums). 83 | Filter(isEven). 84 | Map(toSquare). 85 | Min()) 86 | } 87 | 88 | func TestChainFilterMapPartition(t *testing.T) { 89 | wantLeft := []int{4, 16} 90 | wantRight := []int{36, 64} 91 | left, right := u.NewPipe(nums). 92 | Filter(isEven). 93 | Map(toSquare). 94 | Partition(func(n int) bool { return n < 20 }) 95 | 96 | assert.Equal(t, wantLeft, left) 97 | assert.Equal(t, wantRight, right) 98 | } 99 | 100 | func TestChainFilterMapAny(t *testing.T) { 101 | assert.True(t, u.NewPipe(nums). 102 | Filter(isEven). 103 | Map(toSquare). 104 | Any(func(n int) bool { return n%64 == 0 })) 105 | } 106 | 107 | var nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} 108 | var isEven = func(n int) bool { return n%2 == 0 } 109 | var toSquare = func(n int) int { return n * n } 110 | var sum = func(n, acc int) int { return n + acc } 111 | -------------------------------------------------------------------------------- /pointers.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // ToPointer Convert values to pointers 4 | // 5 | // Instead of: 6 | // v := "value" 7 | // MyPointerVar = &v 8 | // 9 | // Or 10 | // v1 := "value1" 11 | // v2 := 100 12 | // 13 | // obj := Obj{ 14 | // Field1: &v, 15 | // Field2: &v2, 16 | // } 17 | // 18 | // Use: 19 | // MyPointerVar = ToPointer("value") 20 | func ToPointer[T any](in T) *T { 21 | return &in 22 | } 23 | -------------------------------------------------------------------------------- /pointers_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | u "github.com/rjNemo/underscore" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestPointers(t *testing.T) { 12 | variable := 123 13 | var object struct{} 14 | 15 | cases := []struct { 16 | value any 17 | expected bool 18 | }{ 19 | { 20 | value: u.ToPointer("myValue"), 21 | expected: true, 22 | }, 23 | { 24 | value: u.ToPointer(variable), 25 | expected: true, 26 | }, 27 | { 28 | value: &variable, 29 | expected: true, 30 | }, 31 | { 32 | value: nil, 33 | expected: false, 34 | }, 35 | { 36 | value: u.ToPointer(object), 37 | expected: true, 38 | }, 39 | } 40 | 41 | for _, c := range cases { 42 | got := (reflect.ValueOf(c.value).Kind() == reflect.Ptr) 43 | assert.Equal(t, c.expected, got) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /range.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Range creates a sequence of numbers, i.e. u.Range(0, 3) = [0 1 2 3], while u.Range(3, 0) = [3 2 1 0] 4 | func Range(start int, end int) (result []int) { 5 | if start < end { 6 | for i := start; i <= end; i++ { 7 | result = append(result, i) 8 | } 9 | } else { 10 | for i := start; i >= end; i-- { 11 | result = append(result, i) 12 | } 13 | } 14 | 15 | return result 16 | } 17 | -------------------------------------------------------------------------------- /range_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | u "github.com/rjNemo/underscore" 8 | ) 9 | 10 | func Test_Range_Creates_Slices(t *testing.T) { 11 | range1 := u.Range(0, 5) 12 | want1 := []int{0, 1, 2, 3, 4, 5} 13 | 14 | if !reflect.DeepEqual(range1, want1) { 15 | t.Errorf("Expected the result to be %v but we got %v", want1, range1) 16 | } 17 | 18 | range2 := u.Range(5, 0) 19 | want2 := []int{5, 4, 3, 2, 1, 0} 20 | 21 | if !reflect.DeepEqual(range2, want2) { 22 | t.Errorf("Expected the result to be %v but we got %v", want2, range2) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /reduce.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Reduce combine a list of values into a single value. 4 | // acc is the initial state, and each successive step of it should be returned by the reduction function. 5 | func Reduce[T, P any](values []T, reduction func(T, P) P, acc P) P { 6 | for _, v := range values { 7 | acc = reduction(v, acc) 8 | } 9 | return acc 10 | } 11 | -------------------------------------------------------------------------------- /reduce_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestReduce(t *testing.T) { 12 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 13 | reducer := func(n, acc int) int { 14 | return n + acc 15 | } 16 | want := 45 17 | 18 | assert.Equal(t, want, u.Reduce(nums, reducer, 0)) 19 | } 20 | -------------------------------------------------------------------------------- /result.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Result represent the outcome of an operation where failure is possible 4 | type Result[T any] interface { 5 | isResult() //to seal the Result interface 6 | ToValue() (*T, error) 7 | IsSuccess() bool 8 | } 9 | 10 | // Ok is the Result that represents success. 11 | type Ok[T any] struct { 12 | Value *T 13 | } 14 | 15 | func (Ok[T]) isResult() {} 16 | 17 | func (o Ok[T]) ToValue() (*T, error) { 18 | return o.Value, nil 19 | } 20 | 21 | func (o Ok[T]) IsSuccess() bool { 22 | return true 23 | } 24 | 25 | // Err is the Result that represents failure. It implements the error interface 26 | type Err[T any] struct{ Err error } 27 | 28 | func (e Err[T]) ToValue() (*T, error) { 29 | return nil, e.Err 30 | } 31 | 32 | func (e Err[T]) IsSuccess() bool { 33 | return false 34 | } 35 | 36 | func (Err[T]) isResult() {} 37 | 38 | func (e Err[T]) Error() string { 39 | return e.Err.Error() 40 | } 41 | 42 | func ToResult[T any](value *T, err error) Result[T] { 43 | if err != nil { 44 | return Err[T]{ 45 | Err: err, 46 | } 47 | } 48 | return Ok[T]{Value: value} 49 | } 50 | -------------------------------------------------------------------------------- /result_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | u "github.com/rjNemo/underscore" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestSuccess(t *testing.T) { 12 | res := isAnswerToLife(42) 13 | assert.True(t, res.IsSuccess()) 14 | } 15 | 16 | func TestFailure(t *testing.T) { 17 | res := isAnswerToLife(13) 18 | assert.False(t, res.IsSuccess()) 19 | } 20 | 21 | func TestIsOK(t *testing.T) { 22 | res, err := isAnswerToLife(42).ToValue() 23 | assert.NoError(t, err) 24 | assert.Equal(t, "You get it", *res) 25 | } 26 | 27 | func TestIsError(t *testing.T) { 28 | life := isAnswerToLife(13) 29 | res, err := life.ToValue() 30 | assert.Error(t, err) 31 | assert.Equal(t, "nope", life.(u.Err[string]).Error()) 32 | assert.Nil(t, res) 33 | } 34 | 35 | func isAnswerToLife(num int) u.Result[string] { 36 | if num == 42 { 37 | res := "You get it" 38 | return u.ToResult(&res, nil) 39 | } 40 | return u.ToResult[string](nil, errors.New("nope")) 41 | } 42 | -------------------------------------------------------------------------------- /slices.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import ( 4 | "sort" 5 | 6 | "golang.org/x/exp/constraints" 7 | ) 8 | 9 | // SortSliceASC sorts any slice ASCENDING 10 | func SortSliceASC[T constraints.Ordered](s []T) { 11 | sort.SliceStable(s, func(i, j int) bool { 12 | return s[i] < s[j] 13 | }) 14 | } 15 | 16 | // SortSliceDESC sorts any slice DESCENDING 17 | func SortSliceDESC[T constraints.Ordered](s []T) { 18 | sort.SliceStable(s, func(i, j int) bool { 19 | return s[i] > s[j] 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /slices_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestSortSliceAscString(t *testing.T) { 11 | slc := []string{"c", "a", "b"} 12 | expected := []string{"a", "b", "c"} 13 | u.SortSliceASC(slc) 14 | 15 | assert.Equal(t, expected, slc) 16 | } 17 | 18 | func TestSortSliceDescString(t *testing.T) { 19 | slc := []string{"c", "a", "b"} 20 | expected := []string{"c", "b", "a"} 21 | u.SortSliceDESC(slc) 22 | 23 | assert.Equal(t, expected, slc) 24 | } 25 | 26 | func TestSortSliceAscInt(t *testing.T) { 27 | slc := []int{1, 4, 3, 5, 2} 28 | expected := []int{1, 2, 3, 4, 5} 29 | u.SortSliceASC(slc) 30 | 31 | assert.Equal(t, expected, slc) 32 | } 33 | 34 | func TestSortSliceDescInt(t *testing.T) { 35 | slc := []int{1, 4, 3, 5, 2} 36 | expected := []int{5, 4, 3, 2, 1} 37 | u.SortSliceDESC(slc) 38 | 39 | assert.Equal(t, expected, slc) 40 | } 41 | 42 | func TestSortSliceAscFloat64(t *testing.T) { 43 | slc := []float64{1.0, 1.2, 1.1, 1.5, 1.01} 44 | expected := []float64{1, 1.01, 1.1, 1.2, 1.5} 45 | u.SortSliceASC(slc) 46 | 47 | assert.Equal(t, expected, slc) 48 | } 49 | 50 | func TestSortSliceDescFloat64(t *testing.T) { 51 | slc := []float64{1.0, 1.2, 1.1, 1.5, 1.01} 52 | expected := []float64{1.5, 1.2, 1.1, 1.01, 1} 53 | u.SortSliceDESC(slc) 54 | 55 | assert.Equal(t, expected, slc) 56 | } 57 | -------------------------------------------------------------------------------- /sum.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | import "golang.org/x/exp/constraints" 4 | 5 | // Sum adds elements of the slice. 6 | func Sum[T constraints.Ordered](values []T) (sum T) { 7 | for _, v := range values { 8 | sum += v 9 | } 10 | return sum 11 | } 12 | 13 | // SumMap sums the values you select from your struct, basically a sort cut instead of 14 | // having to perform a [Map] followed by a [Sum]. 15 | func SumMap[T any, R constraints.Ordered](list []T, selector func(T) R) (sum R) { 16 | for _, v := range list { 17 | sum += selector(v) 18 | } 19 | 20 | return sum 21 | } 22 | -------------------------------------------------------------------------------- /sum_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | u "github.com/rjNemo/underscore" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestSum(t *testing.T) { 11 | nums := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 12 | want := 45 13 | 14 | assert.Equal(t, want, u.Sum(nums)) 15 | } 16 | 17 | func TestSumMap(t *testing.T) { 18 | nums := []u.Tuple[string, int]{ 19 | {"zero", 0}, 20 | {"one", 1}, 21 | {"two", 2}, 22 | {"three", 3}, 23 | {"four", 4}, 24 | {"five", 5}, 25 | {"six", 6}, 26 | {"seven", 7}, 27 | {"eight", 8}, 28 | {"nine", 9}, 29 | } 30 | want := 45 31 | 32 | assert.Equal(t, want, u.SumMap(nums, func(item u.Tuple[string, int]) int { return item.Right })) 33 | } 34 | -------------------------------------------------------------------------------- /ternary.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Ternary returns the first argument if the condition is true, otherwise the second argument. 4 | // Ternary is a special form of the if statement. It allows you to write code that is more concise and less verbose. 5 | func Ternary[T any](condition bool, pos, neg T) T { 6 | if condition { 7 | return pos 8 | } 9 | return neg 10 | } 11 | -------------------------------------------------------------------------------- /ternary_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestTernary(t *testing.T) { 12 | tests := []struct { 13 | condition bool 14 | want string 15 | }{ 16 | {true, "foo"}, 17 | {false, "bar"}, 18 | } 19 | 20 | for _, tc := range tests { 21 | assert.Equal(t, u.Ternary(tc.condition, "foo", "bar"), tc.want) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tuple.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Tuple is a generic tuple type. 4 | // It is used to return multiple values from a function. 5 | type Tuple[L, R any] struct { 6 | Left L 7 | Right R 8 | } 9 | -------------------------------------------------------------------------------- /unique.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Unique returns a slice of unique values from the given slice. 4 | func Unique[T comparable](values []T) (uniques []T) { 5 | seen := make(map[T]bool, 0) 6 | for _, v := range values { 7 | if _, ok := seen[v]; !ok { 8 | uniques = append(uniques, v) 9 | seen[v] = true 10 | } 11 | } 12 | return uniques 13 | } 14 | -------------------------------------------------------------------------------- /unique_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | 8 | u "github.com/rjNemo/underscore" 9 | ) 10 | 11 | func TestUnique(t *testing.T) { 12 | nums := []int{1, 4, 2, 5, 3, 1, 5, 2, 8, 9} 13 | want := []int{1, 4, 2, 5, 3, 8, 9} 14 | 15 | assert.Equal(t, want, u.Unique(nums)) 16 | } 17 | -------------------------------------------------------------------------------- /zip.go: -------------------------------------------------------------------------------- 1 | package underscore 2 | 3 | // Zip joins two slices together so all the elements of left slice are attached to the corresponding 4 | // elements of the right slice, i.e. [one two three] [1 2 3 4] = [{one, 1} {two, 2} {three, 3}] 5 | // the returned data will be the size of the smallest slice 6 | func Zip[L any, R any](left []L, right []R) []Tuple[L, R] { 7 | shortest := 0 8 | if len(left) < len(right) { 9 | shortest = len(left) 10 | } else { 11 | shortest = len(right) 12 | } 13 | 14 | results := make([]Tuple[L, R], shortest) 15 | for i := 0; i < shortest; i++ { 16 | results[i] = Tuple[L, R]{Left: left[i], Right: right[i]} 17 | } 18 | 19 | return results 20 | } 21 | -------------------------------------------------------------------------------- /zip_test.go: -------------------------------------------------------------------------------- 1 | package underscore_test 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | 7 | u "github.com/rjNemo/underscore" 8 | ) 9 | 10 | func Test_Zip_Can_Zip_Two_Equal_Sized_Slices(t *testing.T) { 11 | left := []string{"Left 1", "Left 2", "Left 3"} 12 | right := []int{1, 2, 3} 13 | 14 | var zipped = u.Zip(left, right) 15 | 16 | want := []u.Tuple[string, int]{ 17 | {Left: "Left 1", Right: 1}, 18 | {Left: "Left 2", Right: 2}, 19 | {Left: "Left 3", Right: 3}, 20 | } 21 | 22 | if !reflect.DeepEqual(zipped, want) { 23 | t.Errorf("Expected the result to be %v but we got %v", want, zipped) 24 | } 25 | } 26 | 27 | func Test_Zip_Can_Zip_Two_Different_Sized_Slices_Left_Larger(t *testing.T) { 28 | left := []string{"Left 1", "Left 2", "Left 3", "Left 4"} 29 | right := []int{1, 2, 3} 30 | 31 | var zipped = u.Zip(left, right) 32 | if len(zipped) != 3 { 33 | t.Errorf("Expected the result of Zip(left, right) to have a length of 3 but got %v", len(zipped)) 34 | } 35 | 36 | want := []u.Tuple[string, int]{ 37 | {Left: "Left 1", Right: 1}, 38 | {Left: "Left 2", Right: 2}, 39 | {Left: "Left 3", Right: 3}, 40 | } 41 | 42 | if !reflect.DeepEqual(zipped, want) { 43 | t.Errorf("Expected the result to be %v but we got %v", want, zipped) 44 | } 45 | } 46 | 47 | func Test_Zip_Can_Zip_Two_Different_Sized_Slices_Right_Larger(t *testing.T) { 48 | left := []string{"Left 1", "Left 2", "Left 3"} 49 | right := []int{1, 2, 3, 4} 50 | 51 | var zipped = u.Zip(left, right) 52 | if len(zipped) != 3 { 53 | t.Errorf("Expected the result of Zip(left, right) to have a length of 3 but got %v", len(zipped)) 54 | } 55 | 56 | want := []u.Tuple[string, int]{ 57 | {Left: "Left 1", Right: 1}, 58 | {Left: "Left 2", Right: 2}, 59 | {Left: "Left 3", Right: 3}, 60 | } 61 | 62 | if !reflect.DeepEqual(zipped, want) { 63 | t.Errorf("Expected the result to be %v but we got %v", want, zipped) 64 | } 65 | } 66 | --------------------------------------------------------------------------------