├── .github └── workflows │ └── build.yml ├── .gitignore ├── .goreleaser.yml ├── .pre-commit-config.yaml ├── Dockerfile ├── Dockerfile-goreleaser ├── LICENSE ├── LICENSE-apache.txt ├── NOTICE.txt ├── Pipfile ├── Pipfile.lock ├── README.md ├── Taskfile.yml ├── bats-test ├── GEN_ALL.sh ├── TEST_ALL.sh ├── cluster_generate.sh ├── cluster_test.sh ├── data │ ├── clusters │ │ ├── bats │ │ │ ├── cluster.jsonnet │ │ │ └── params.jsonnet │ │ └── params.jsonnet │ ├── components │ │ ├── comp1 │ │ │ ├── comp1.jsonnet │ │ │ ├── comp1_list.jsonnet │ │ │ └── params.jsonnet │ │ └── comp2 │ │ │ ├── comp2.jsonnet │ │ │ └── params.jsonnet │ └── misc │ │ ├── README.md │ │ ├── basic.json │ │ ├── basic.jsonnet │ │ ├── clean.yaml │ │ ├── cluster_params.jsonnet │ │ ├── dirty.yaml │ │ ├── fail.yaml │ │ └── nokind.yaml ├── expected │ ├── cluster_components │ ├── cluster_list │ ├── cluster_params │ ├── cluster_params_comp1 │ ├── cluster_params_comp2 │ ├── cluster_params_file │ ├── cluster_params_no_comp │ ├── get_params │ ├── get_params_comp1 │ ├── get_params_comp2 │ ├── jsonnet_basic_json │ ├── jsonnet_basic_jsonnet │ ├── jsonnet_comp1_json │ ├── jsonnet_comp1_list_json │ ├── jsonnet_comp1_list_stream │ ├── jsonnet_comp1_list_yaml │ ├── jsonnet_comp1_yaml │ ├── jsonnet_comp2_with_file_yaml │ └── yaml_helmclean_clean ├── get_generate.sh ├── get_test.sh ├── init_test.sh ├── jsonnet_generate.sh ├── jsonnet_test.sh ├── render_test.sh ├── yaml_generate.sh └── yaml_test.sh ├── cmd ├── cluster.go ├── directories.go ├── generate.go ├── get.go ├── init.go ├── json.go ├── jsonnet.go ├── render.go ├── root.go ├── types.go ├── vars.go ├── version.go └── yaml.go ├── docs ├── building.md ├── components │ ├── helm.md │ ├── jk.md │ ├── jsonnet.md │ └── yaml.md ├── concepts │ ├── clusters.md │ ├── components.md │ ├── helpers.md │ └── overview.md ├── index.md └── installation │ ├── dependencies.md │ ├── linux.md │ └── osx.md ├── go.mod ├── go.sum ├── main.go ├── mkdocs.yml ├── scripts └── kr8-helpers └── site ├── 404.html ├── assets ├── fonts │ ├── font-awesome.css │ ├── material-icons.css │ └── specimen │ │ ├── FontAwesome.ttf │ │ ├── FontAwesome.woff │ │ ├── FontAwesome.woff2 │ │ ├── MaterialIcons-Regular.ttf │ │ ├── MaterialIcons-Regular.woff │ │ └── MaterialIcons-Regular.woff2 ├── images │ ├── favicon.png │ └── icons │ │ ├── bitbucket.1b09e088.svg │ │ ├── github.f0b8504a.svg │ │ └── gitlab.6dd19c00.svg ├── javascripts │ ├── application.c648116f.js │ ├── lunr │ │ ├── lunr.da.js │ │ ├── lunr.de.js │ │ ├── lunr.du.js │ │ ├── lunr.es.js │ │ ├── lunr.fi.js │ │ ├── lunr.fr.js │ │ ├── lunr.hu.js │ │ ├── lunr.it.js │ │ ├── lunr.ja.js │ │ ├── lunr.jp.js │ │ ├── lunr.multi.js │ │ ├── lunr.nl.js │ │ ├── lunr.no.js │ │ ├── lunr.pt.js │ │ ├── lunr.ro.js │ │ ├── lunr.ru.js │ │ ├── lunr.stemmer.support.js │ │ ├── lunr.sv.js │ │ ├── lunr.th.js │ │ ├── lunr.tr.js │ │ ├── tinyseg.js │ │ └── wordcut.js │ └── modernizr.74668098.js └── stylesheets │ ├── application-palette.a8b3c06d.css │ └── application.30686662.css ├── components ├── helm │ └── index.html ├── jk │ └── index.html ├── jsonnet │ └── index.html └── yaml │ └── index.html ├── concepts ├── clusters │ └── index.html ├── components │ └── index.html ├── helpers │ └── index.html └── overview │ └── index.html ├── index.html ├── installation ├── dependencies │ └── index.html ├── linux │ └── index.html └── osx │ └── index.html ├── search └── search_index.json ├── sitemap.xml └── sitemap.xml.gz /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | tags: 8 | - 'v*' 9 | pull_request: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - 16 | name: Checkout 17 | uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 20 | - 21 | name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: 1.22.0 25 | - 26 | name: Cache Go modules 27 | uses: actions/cache@v1 28 | with: 29 | path: ~/go/pkg/mod 30 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 31 | restore-keys: | 32 | ${{ runner.os }}-go- 33 | - 34 | name: Docker Login 35 | uses: docker/login-action@v1 36 | with: 37 | registry: ghcr.io 38 | username: ${{ github.repository_owner }} 39 | password: ${{ secrets.GITHUB_TOKEN }} 40 | - 41 | name: Run GoReleaser 42 | uses: goreleaser/goreleaser-action@v6 43 | if: success() && startsWith(github.ref, 'refs/tags/') 44 | with: 45 | version: latest 46 | args: release --rm-dist 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | dist/ 3 | bin 4 | *.tar.gz 5 | kr8 6 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: kr8 2 | version: 2 3 | before: 4 | hooks: 5 | - go mod download 6 | builds: 7 | - env: [CGO_ENABLED=0] 8 | goos: 9 | - linux 10 | - darwin 11 | goarch: 12 | - amd64 13 | main: . 14 | ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} 15 | binary: kr8 16 | archives: 17 | - format: tar.gz 18 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}' 19 | files: 20 | - LICENSE* 21 | - README* 22 | - CHANGELOG* 23 | - scripts/* 24 | - docs/* 25 | snapshot: 26 | name_template: SNAPSHOT-{{ .Commit }} 27 | dist: dist 28 | dockers: 29 | - 30 | image_templates: 31 | - 'ghcr.io/apptio/kr8:{{ .Tag }}' 32 | - 'ghcr.io/apptio/kr8:latest' 33 | dockerfile: Dockerfile-goreleaser 34 | build_flag_templates: 35 | - "--label=org.label-schema.schema-version=1.0" 36 | - "--label=org.label-schema.version={{.Version}}" 37 | - "--label=org.label-schema.name={{.ProjectName}}" 38 | nfpms: 39 | - 40 | vendor: Apptio TechOps 41 | homepage: "https://github.com/apptio/kr8" 42 | maintainer: 'Apptio, an IBM Company' 43 | description: "Opinionated configuration management tool for Kubernetes Cluster" 44 | license: MIT 45 | formats: 46 | - rpm 47 | - deb 48 | bindir: /usr/local/bin 49 | brews: 50 | - name: kr8 51 | url_template: "https://github.com/apptio/kr8/releases/download/{{ .Tag }}/{{ .ArtifactName }}" 52 | url_headers: 53 | - "Accept: application/octet-stream" 54 | - 'Authorization: bearer #{ENV["HOMEBREW_TAP_GITHUB_TOKEN"]}' 55 | download_strategy: CurlDownloadStrategy 56 | repository: 57 | owner: Apptio 58 | name: homebrew-tap 59 | branch: main 60 | pull_request: 61 | enabled: true 62 | git: 63 | url: 'git@github.com:apptio/homebrew-tap.git' 64 | private_key: '{{ .Env.PRIVATE_KEY_PATH }}' 65 | 66 | commit_author: 67 | name: release 68 | email: release@apptio.com 69 | commit_msg_template: "Brew formula update for {{ .ProjectName }} version {{ .Tag }}" 70 | 71 | homepage: "http://apptio.github.io/kr8" 72 | description: "Opinionated configuration management tool for Kubernetes Cluster" 73 | license: MIT 74 | install: | 75 | bin.install "kr8" 76 | bin.install "scripts/kr8-helpers" 77 | dependencies: 78 | - helm 79 | - jsonnet 80 | - go-task/tap/go-task 81 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | - repo: git://github.com/dnephin/pre-commit-golang 2 | rev: master 3 | hooks: 4 | - id: go-fmt 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18.3-alpine3.16 2 | 3 | WORKDIR /app 4 | 5 | COPY . /app 6 | 7 | ARG VERSION 8 | 9 | RUN apk add git build-base \ 10 | && go mod download \ 11 | && go build -o kr8 -ldflags "-X main.version=${VERSION}" 12 | 13 | ENTRYPOINT ["/app/kr8"] 14 | -------------------------------------------------------------------------------- /Dockerfile-goreleaser: -------------------------------------------------------------------------------- 1 | FROM scratch 2 | 3 | WORKDIR /app 4 | 5 | COPY ./kr8 /app 6 | 7 | ENTRYPOINT ["/app/kr8"] 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2018 Apptio 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | -- 2 | This product includes portions of the kubecfg project 3 | 4 | Copyright 2018 Kubecfg. 5 | 6 | Licensed under the Apache License v2.0 7 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | name = "pypi" 3 | url = "https://pypi.org/simple" 4 | verify_ssl = true 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | mkdocs = "*" 10 | mkdocs-material = "*" 11 | 12 | [requires] 13 | python_version = "2.7" 14 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "5f90de643bb20c0b6977b04abcea83227b6abf7b8040dbf731bfab35aa3dc702" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "2.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "click": { 20 | "hashes": [ 21 | "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", 22 | "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" 23 | ], 24 | "version": "==7.0" 25 | }, 26 | "htmlmin": { 27 | "hashes": [ 28 | "sha256:07842e6d03a030f8e39eeadfd5fd715607b26a9f5fdcd926f1ce80c7a4984bfa", 29 | "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178" 30 | ], 31 | "version": "==0.1.12" 32 | }, 33 | "jinja2": { 34 | "hashes": [ 35 | "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", 36 | "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" 37 | ], 38 | "version": "==2.10.1" 39 | }, 40 | "jsmin": { 41 | "hashes": [ 42 | "sha256:b6df99b2cd1c75d9d342e4335b535789b8da9107ec748212706ef7bbe5c2553b", 43 | "sha256:eb0f6168b17b501f99bb6460ada2b7a899f2debf8cb2d8f1ff73ffc1e49498a0" 44 | ], 45 | "version": "==2.2.2" 46 | }, 47 | "livereload": { 48 | "hashes": [ 49 | "sha256:78d55f2c268a8823ba499305dcac64e28ddeb9a92571e12d543cd304faf5817b", 50 | "sha256:89254f78d7529d7ea0a3417d224c34287ebfe266b05e67e51facaf82c27f0f66" 51 | ], 52 | "version": "==2.6.1" 53 | }, 54 | "markdown": { 55 | "hashes": [ 56 | "sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a", 57 | "sha256:56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c" 58 | ], 59 | "version": "==3.1.1" 60 | }, 61 | "markupsafe": { 62 | "hashes": [ 63 | "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", 64 | "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", 65 | "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", 66 | "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", 67 | "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", 68 | "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", 69 | "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", 70 | "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", 71 | "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", 72 | "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", 73 | "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", 74 | "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", 75 | "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", 76 | "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", 77 | "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", 78 | "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", 79 | "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", 80 | "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", 81 | "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", 82 | "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", 83 | "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", 84 | "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", 85 | "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", 86 | "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", 87 | "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", 88 | "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", 89 | "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", 90 | "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" 91 | ], 92 | "version": "==1.1.1" 93 | }, 94 | "mkdocs": { 95 | "hashes": [ 96 | "sha256:17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939", 97 | "sha256:8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a" 98 | ], 99 | "index": "pypi", 100 | "version": "==1.0.4" 101 | }, 102 | "mkdocs-material": { 103 | "hashes": [ 104 | "sha256:08d94bc46211926fd70b7166e64a0d2155324d9a9652f5e0a7f8922468d9c8ac", 105 | "sha256:bf904bfe79491275c462d8f0b56f17abddad60dcc0b01c59619ad6432708d5ed" 106 | ], 107 | "index": "pypi", 108 | "version": "==4.4.1" 109 | }, 110 | "mkdocs-minify-plugin": { 111 | "hashes": [ 112 | "sha256:3000a5069dd0f42f56a8aaf7fd5ea1222c67487949617e39585d6b6434b074b6", 113 | "sha256:d54fdd5be6843dd29fd7af2f7fdd20a9eb4db46f1f6bed914e03b2f58d2d488e" 114 | ], 115 | "version": "==0.2.1" 116 | }, 117 | "pygments": { 118 | "hashes": [ 119 | "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", 120 | "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" 121 | ], 122 | "version": "==2.4.2" 123 | }, 124 | "pymdown-extensions": { 125 | "hashes": [ 126 | "sha256:25b0a7967fa697b5035e23340a48594e3e93acb10b06d74574218ace3347d1df", 127 | "sha256:6cf0cf36b5a03b291ace22dc2f320f4789ce56fbdb6635a3be5fadbf5d7694dd" 128 | ], 129 | "version": "==6.0" 130 | }, 131 | "pyyaml": { 132 | "hashes": [ 133 | "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", 134 | "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", 135 | "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", 136 | "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", 137 | "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", 138 | "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", 139 | "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", 140 | "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", 141 | "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", 142 | "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", 143 | "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", 144 | "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", 145 | "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" 146 | ], 147 | "version": "==5.1.2" 148 | }, 149 | "six": { 150 | "hashes": [ 151 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 152 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 153 | ], 154 | "version": "==1.12.0" 155 | }, 156 | "tornado": { 157 | "hashes": [ 158 | "sha256:0662d28b1ca9f67108c7e3b77afabfb9c7e87bde174fbda78186ecedc2499a9d", 159 | "sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409", 160 | "sha256:732e836008c708de2e89a31cb2fa6c0e5a70cb60492bee6f1ea1047500feaf7f", 161 | "sha256:8154ec22c450df4e06b35f131adc4f2f3a12ec85981a203301d310abf580500f", 162 | "sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5", 163 | "sha256:d4b3e5329f572f055b587efc57d29bd051589fb5a43ec8898c77a47ec2fa2bbb", 164 | "sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444" 165 | ], 166 | "version": "==5.1.1" 167 | } 168 | }, 169 | "develop": {} 170 | } 171 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kr8 2 | 3 | kr8 is a very opinionated tool used for rendering [jsonnet](http://jsonnet.org) manifests for numerous Kubernetes clusters. 4 | 5 | It has been designed to work like a simple configuration management framework, allowing operators to specify configuration for _components_ across multiple clusters. 6 | 7 | kr8 is a work in progress (currently in Alpha), but is in use at Apptio for managing components of multiple Kubernetes clusters. 8 | 9 | For more information about the inspiration and the problem kr8 solves, check out this [blog post](https://leebriggs.co.uk/blog/2018/05/08/kubernetes-config-mgmt.html). 10 | 11 | kr8 consists of: 12 | 13 | - kr8 - a Go binary for rendering manifests 14 | - [Task](https://github.com/go-task/task) - a third party Go binary for executing tasks 15 | - Configs - A configuration directory which contains config for clusters and the components installed into those clusters 16 | 17 | kr8 is not designed to be a tool to help you install and deploy applications. It's specifically designed to manage and maintain configuration for the cluster level services. For more information, see the [components](docs/components) section. 18 | 19 | In order to use kr8, you'll need a configuration repository to go with this binary. See the [example](https://github.com/apptio/kr8-configs) repo for more information. 20 | 21 | # Features 22 | 23 | - Generate and customize component configuration for Kubernetes clusters across environments, regions and platforms 24 | - Opinionated config, flexible deployment. kr8 simply generates manifests for you, you decide how to deploy them 25 | - Render and override component config from multiple sources, such as Helm, Kustomize and static manifests 26 | - CI/CD friendly 27 | 28 | # Concepts & Tools 29 | 30 | ## Component 31 | 32 | A component is something you install in your cluster to make it function and work as you expect. Some examples of components might be: 33 | 34 | - [cert-manager](https://github.com/jetstack/cert-manager) 35 | - [nginx-ingress](https://github.com/kubernetes/ingress-nginx) 36 | - [sealed-secrets](https://github.com/bitnami-labs/sealed-secrets) 37 | 38 | Components are _not_ the applications you want to run in your cluster. Components are generally applications you'd run in your cluster to make those applications function and work as expected. 39 | 40 | ## Clusters 41 | 42 | A cluster is a Kubernetes cluster running in a cloud provider, datacenter or elsewhere. You will more than likely have multiple clusters across multiple environments and regions. 43 | 44 | Clusters have: 45 | 46 | - Cluster configuration, which can be used as part of the Jsonnet configuration later. This consists of things like the cluster name, type, region etc 47 | - Components, which you'd like to install in a cluster 48 | - Component configuration, which is modifications to a component which are specific to a cluster. An example of this might be the path to an SSL certificate for the nginx-ingress controller, which may be different across cloud providers. 49 | 50 | ## Taskfiles 51 | 52 | Instead of reinventing the wheel, the kr8 ecosystem makes uses of the [Task](https://github.com/go-task/task) tool to generate the cluster configuration. The task files generally call kr8 in order to render the manifests for a component. We chose task because it supports yaml and json configuration files, which mean we can continue to leverage jsonnet to write taskfiles where needed. 53 | 54 | ## Jsonnet 55 | 56 | All configuration for kr8 is written in [Jsonnet](https://jsonnet.org/). Jsonnet was chosen because it allows us to use code for configuration, while staying as close to JSON as possible. 57 | 58 | # Building 59 | 60 | See the [Building](docs/building.md) documentation. 61 | 62 | # Contributing 63 | 64 | Fork the repo in github and send a merge request! 65 | 66 | # Caveats 67 | 68 | There are currently no tests, and the code is not very [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). 69 | 70 | This was (one of) Apptio's first exercise in Go, and pull requests are very welcome. 71 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | tasks: 4 | default: 5 | cmds: 6 | - task: build 7 | 8 | build: 9 | desc: Build kr8 for your local system 10 | cmds: 11 | - go build 12 | 13 | build-snapshot: 14 | desc: Build a snapshot for all platforms using goreleaser 15 | cmds: 16 | - goreleaser release --snapshot --clean --skip=homebrew,docker 17 | 18 | mkdocs: 19 | desc: Install mkdocs 20 | cmds: 21 | - pipenv install mkdocs 22 | - pipenv install mkdocs-material 23 | web-local: 24 | desc: Run the site locally 25 | cmds: 26 | - pipenv run mkdocs serve 27 | web-deploy: 28 | desc: Build website assets 29 | cmds: 30 | - pipenv run mkdocs build 31 | - pipenv run mkdocs gh-deploy 32 | -------------------------------------------------------------------------------- /bats-test/GEN_ALL.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | for i in cluster get jsonnet yaml; do 6 | echo "Generating expected output for '$i' command" 7 | ${i}_generate.sh 8 | done 9 | -------------------------------------------------------------------------------- /bats-test/TEST_ALL.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in cluster get init jsonnet render yaml; do 4 | echo "Testing '$i' command" 5 | ${i}_test.sh 6 | echo 7 | done 8 | -------------------------------------------------------------------------------- /bats-test/cluster_generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$KR8" ]; then 4 | KR8=kr8 5 | fi 6 | 7 | KR8_ARGS="-d data" 8 | CLUSTER=bats 9 | 10 | $KR8 $KR8_ARGS cluster list > expected/cluster_list 11 | $KR8 $KR8_ARGS cluster components --cluster $CLUSTER > expected/cluster_components 12 | $KR8 $KR8_ARGS cluster params --cluster $CLUSTER > expected/cluster_params 13 | $KR8 $KR8_ARGS cluster params --cluster $CLUSTER -C comp1 > expected/cluster_params_comp1 14 | $KR8 $KR8_ARGS cluster params --cluster $CLUSTER -P comp2 > expected/cluster_params_comp2 15 | $KR8 $KR8_ARGS cluster params --cluster $CLUSTER --clusterparams data/misc/cluster_params.jsonnet > expected/cluster_params_file 16 | # This is an odd case, but creates unique output, while -P intentionally fails 17 | $KR8 $KR8_ARGS cluster params --cluster $CLUSTER -C no_component > expected/cluster_params_no_comp 18 | -------------------------------------------------------------------------------- /bats-test/cluster_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | if [ -z "$KR8" ]; then 4 | KR8=kr8 5 | fi 6 | 7 | KR8_ARGS="-d data" 8 | CLUSTER=bats 9 | 10 | @test "Check cluster list output" { 11 | expected=$(/params.jsonnet hierarchy bleed into the 26 | ## params no matter which component is requested. Is this correct? 27 | ## "comp1" displays this behavior in a test in case it changes 28 | 29 | @test "Check cluster params for all components" { 30 | expected=$( expected/get_params 12 | $KR8 $KR8_ARGS get params --cluster $CLUSTER -C comp1 > expected/get_params_comp1 13 | $KR8 $KR8_ARGS get params --cluster $CLUSTER -P comp2 > expected/get_params_comp2 14 | 15 | -------------------------------------------------------------------------------- /bats-test/get_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | if [ -z "$KR8" ]; then 4 | KR8=kr8 5 | fi 6 | 7 | KR8_ARGS="-d data" 8 | CLUSTER=bats 9 | 10 | # NOTE: These are expected to be the same as "cluster ..." output, so reuse 11 | # the expected files. --clusterparams might throw a wrench in this 12 | 13 | @test "Check get clusters output" { 14 | expected=$( expected/jsonnet_basic_json 12 | $KR8 $KR8_ARGS jsonnet render data/misc/basic.jsonnet > expected/jsonnet_basic_jsonnet 13 | 14 | # Cluster/component parsing, json or yaml will handle single objects 15 | $KR8 $KR8_ARGS jsonnet render -C comp1 -F json data/components/comp1/comp1.jsonnet > expected/jsonnet_comp1_json 16 | $KR8 $KR8_ARGS jsonnet render -C comp1 -F yaml data/components/comp1/comp1.jsonnet > expected/jsonnet_comp1_yaml 17 | 18 | # All formats handle list parsing 19 | $KR8 $KR8_ARGS jsonnet render -C comp1 -F json data/components/comp1/comp1_list.jsonnet > expected/jsonnet_comp1_list_json 20 | $KR8 $KR8_ARGS jsonnet render -C comp1 -F yaml data/components/comp1/comp1_list.jsonnet > expected/jsonnet_comp1_list_yaml 21 | $KR8 $KR8_ARGS jsonnet render -C comp1 -F stream data/components/comp1/comp1_list.jsonnet > expected/jsonnet_comp1_list_stream 22 | 23 | # With --clusterparams 24 | $KR8 $KR8_ARGS jsonnet render -C comp2 -F yaml data/components/comp2/comp2.jsonnet \ 25 | --clusterparams data/misc/cluster_params.jsonnet > expected/jsonnet_comp2_with_file_yaml 26 | -------------------------------------------------------------------------------- /bats-test/jsonnet_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | # FIXME: Add --prune tests 4 | 5 | if [ -z "$KR8" ]; then 6 | KR8=kr8 7 | fi 8 | 9 | KR8_ARGS="-d data" 10 | CLUSTER=bats 11 | 12 | @test "Check jsonnet json parsing" { 13 | expected=$( expected/yaml_helmclean_clean 9 | -------------------------------------------------------------------------------- /bats-test/yaml_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | if [ -z "$KR8" ]; then 4 | KR8=kr8 5 | fi 6 | 7 | KR8_ARGS="-d data" 8 | CLUSTER=bats 9 | 10 | # Stacktrace on bad YAML 11 | # FIXME: could be better 12 | @test "Check yaml helmclean on bad YAML - FAIL" { 13 | run $KR8 $KR8_ARGS yaml helmclean < data/misc/fail.yaml 14 | [ "$status" -eq 2 ] 15 | } 16 | 17 | # Stacktrace if we don't match "kind" or other k8sy things 18 | # FIXME: could be better 19 | @test "Check yaml helmclean object without kind - FAIL" { 20 | run $KR8 $KR8_ARGS yaml helmclean < data/misc/nokind.yaml 21 | [ "$status" -eq 2 ] 22 | } 23 | @test "Check yaml helmclean stream with no nulls" { 24 | expected=$( 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package cmd 22 | 23 | import ( 24 | "fmt" 25 | "os" 26 | 27 | "github.com/olekukonko/tablewriter" 28 | "github.com/rs/zerolog/log" 29 | "github.com/spf13/cobra" 30 | "github.com/spf13/viper" 31 | "github.com/tidwall/gjson" 32 | ) 33 | 34 | // clusterCmd represents the cluster command 35 | var clusterCmd = &cobra.Command{ 36 | Use: "cluster", 37 | Short: "Operate on kr8 clusters", 38 | Long: `Manage, list and generate kr8 cluster configurations at the cluster scope`, 39 | //Run: func(cmd *cobra.Command, args []string) { }, 40 | } 41 | 42 | var listCmd = &cobra.Command{ 43 | Use: "list", 44 | Short: "List Clusters", 45 | Long: "List Clusters in kr8 config hierarchy", 46 | Run: func(cmd *cobra.Command, args []string) { 47 | 48 | clusters, err := getClusters(clusterDir) 49 | 50 | if err != nil { 51 | log.Fatal().Err(err).Msg("Error getting cluster") 52 | } 53 | 54 | var entry []string 55 | table := tablewriter.NewWriter(os.Stdout) 56 | table.SetHeader([]string{"Name", "Path"}) 57 | 58 | for _, c := range clusters.Cluster { 59 | entry = append(entry, c.Name) 60 | entry = append(entry, c.Path) 61 | table.Append(entry) 62 | entry = entry[:0] 63 | } 64 | table.Render() 65 | 66 | }, 67 | } 68 | 69 | var paramsCmd = &cobra.Command{ 70 | Use: "params", 71 | Short: "Show Cluster Params", 72 | Long: "Show cluster params in kr8 config hierarchy", 73 | Run: func(cmd *cobra.Command, args []string) { 74 | viper.BindPFlag("cluster", clusterCmd.PersistentFlags().Lookup("cluster")) 75 | clusterName := viper.GetString("cluster") 76 | 77 | if clusterName == "" && clusterParams == "" { 78 | log.Fatal().Msg("Please specify a --cluster name and/or --clusterparams") 79 | } 80 | 81 | var clist []string 82 | if componentName != "" { 83 | clist = append(clist, componentName) 84 | } 85 | j := renderClusterParams(cmd, clusterName, clist, clusterParams, false) 86 | 87 | if paramPath != "" { 88 | value := gjson.Get(j, paramPath) 89 | notunset, _ := cmd.Flags().GetBool("notunset") 90 | if notunset && value.String() == "" { 91 | log.Fatal().Msg("Error getting param: " + paramPath) 92 | } else { 93 | fmt.Println(value) // no formatting because this isn't always json, this is just the value of a field 94 | } 95 | } else { 96 | formatted := Pretty(j, colorOutput) 97 | fmt.Println(formatted) 98 | } 99 | 100 | }, 101 | } 102 | 103 | var componentsCmd = &cobra.Command{ 104 | Use: "components", 105 | Short: "Show Cluster Components", 106 | Long: "Show the components to be installed in the cluster in the kr8 hierarchy", 107 | Run: func(cmd *cobra.Command, args []string) { 108 | viper.BindPFlag("cluster", clusterCmd.PersistentFlags().Lookup("cluster")) 109 | clusterName := viper.GetString("cluster") 110 | 111 | if clusterName == "" && clusterParams == "" { 112 | log.Fatal().Msg("Please specify a --cluster name and/or --clusterparams") 113 | } 114 | 115 | var params []string 116 | if clusterName != "" { 117 | clusterPath := getCluster(clusterDir, clusterName) 118 | params = getClusterParams(clusterDir, clusterPath) 119 | } 120 | if clusterParams != "" { 121 | params = append(params, clusterParams) 122 | } 123 | 124 | j := renderJsonnet(cmd, params, "._components", true, "", "clustercomponents") 125 | if paramPath != "" { 126 | value := gjson.Get(j, paramPath) 127 | if value.String() == "" { 128 | log.Fatal().Msg("Error getting param: " + paramPath) 129 | } else { 130 | formatted := Pretty(j, colorOutput) 131 | fmt.Println(formatted) 132 | } 133 | } else { 134 | formatted := Pretty(j, colorOutput) 135 | fmt.Println(formatted) 136 | } 137 | 138 | }, 139 | } 140 | 141 | func init() { 142 | RootCmd.AddCommand(clusterCmd) 143 | clusterCmd.AddCommand(listCmd) 144 | clusterCmd.AddCommand(paramsCmd) 145 | clusterCmd.AddCommand(componentsCmd) 146 | clusterCmd.PersistentFlags().StringP("cluster", "c", "", "cluster to operate on") 147 | clusterCmd.PersistentFlags().StringVarP(&clusterParams, "clusterparams", "", "", "provide cluster params as single file - can be combined with --cluster to override cluster") 148 | paramsCmd.PersistentFlags().StringVarP(&componentName, "component", "C", "", "component to render params for") 149 | paramsCmd.Flags().StringVarP(¶mPath, "param", "P", "", "return value of json param from supplied path") 150 | paramsCmd.Flags().BoolP("notunset", "", false, "Fail if specified param is not set. Otherwise returns blank value if param is not set") 151 | } 152 | -------------------------------------------------------------------------------- /cmd/directories.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/rs/zerolog/log" 7 | "github.com/spf13/cobra" 8 | "github.com/tidwall/gjson" 9 | "io/ioutil" 10 | "os" 11 | "path/filepath" 12 | "strings" 13 | ) 14 | 15 | type componentDef struct { 16 | Path string `json:"path"` 17 | } 18 | 19 | func (c *Clusters) addItem(item Cluster) Clusters { 20 | c.Cluster = append(c.Cluster, item) 21 | return *c 22 | } 23 | 24 | func getClusters(searchDir string) (Clusters, error) { 25 | 26 | fileList := make([]string, 0) 27 | 28 | e := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error { 29 | fileList = append(fileList, path) 30 | return err 31 | }) 32 | 33 | if e != nil { 34 | log.Fatal().Err(e).Msg("Error building cluster list: ") 35 | 36 | } 37 | 38 | ClusterData := []Cluster{} 39 | c := Clusters{ClusterData} 40 | 41 | for _, file := range fileList { 42 | 43 | splitFile := strings.Split(file, "/") 44 | // get the filename 45 | fileName := splitFile[len(splitFile)-1] 46 | 47 | if fileName == "cluster.jsonnet" { 48 | entry := Cluster{Name: splitFile[len(splitFile)-2], Path: strings.Join(splitFile[:len(splitFile)-1], "/")} 49 | c.addItem(entry) 50 | 51 | } 52 | } 53 | 54 | return c, nil 55 | 56 | } 57 | 58 | func getCluster(searchDir string, clusterName string) string { 59 | 60 | var clusterPath string 61 | 62 | e := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error { 63 | dir, file := filepath.Split(path) 64 | if filepath.Base(dir) == clusterName && file == "cluster.jsonnet" { 65 | clusterPath = path 66 | return nil 67 | } else { 68 | return err 69 | } 70 | }) 71 | 72 | if e != nil { 73 | log.Fatal().Err(e).Msg("Error building cluster list: ") 74 | 75 | } 76 | 77 | if clusterPath == "" { 78 | log.Fatal().Msg("Could not find cluster: " + clusterName) 79 | } 80 | 81 | return clusterPath 82 | 83 | } 84 | 85 | func getClusterParams(basePath string, targetPath string) []string { 86 | 87 | // a slice to store results 88 | var results []string 89 | results = append(results, targetPath) 90 | 91 | // remove the cluster.jsonnet 92 | splitFile := strings.Split(targetPath, "/") 93 | 94 | // gets the targetdir without the cluster.jsonnet 95 | targetDir := strings.Join(splitFile[:len(splitFile)-1], "/") 96 | 97 | // walk through the directory hierachy 98 | for { 99 | rel, _ := filepath.Rel(basePath, targetDir) 100 | 101 | // check if there's a params.json in the folder 102 | if _, err := os.Stat(targetDir + "/params.jsonnet"); err == nil { 103 | results = append(results, targetDir+"/params.jsonnet") 104 | } 105 | 106 | // stop if we're in the basePath 107 | if rel == "." { 108 | break 109 | } 110 | 111 | // next! 112 | targetDir += "/.." 113 | } 114 | 115 | // jsonnet's import order matters, so we need to reverse the slice 116 | last := len(results) - 1 117 | for i := 0; i < len(results)/2; i++ { 118 | results[i], results[last-i] = results[last-i], results[i] 119 | } 120 | 121 | return results 122 | 123 | } 124 | 125 | // only render cluster params (_cluster), without components 126 | func renderClusterParamsOnly(cmd *cobra.Command, clusterName string, clusterParams string, prune bool) string { 127 | var params []string 128 | if clusterName != "" { 129 | clusterPath := getCluster(clusterDir, clusterName) 130 | params = getClusterParams(clusterDir, clusterPath) 131 | } 132 | if clusterParams != "" { 133 | params = append(params, clusterParams) 134 | } 135 | renderedParams := renderJsonnet(cmd, params, "._cluster", prune, "", "clusterparams") 136 | 137 | return renderedParams 138 | } 139 | 140 | // render cluster params, merged with one or more component's parameters. Empty componentName list renders all component parameters 141 | func renderClusterParams(cmd *cobra.Command, clusterName string, componentNames []string, clusterParams string, prune bool) string { 142 | if clusterName == "" && clusterParams == "" { 143 | log.Fatal().Msg("Please specify a --cluster name and/or --clusterparams") 144 | } 145 | 146 | var params []string 147 | var componentMap map[string]componentDef 148 | 149 | if clusterName != "" { 150 | clusterPath := getCluster(clusterDir, clusterName) 151 | params = getClusterParams(clusterDir, clusterPath) 152 | } 153 | if clusterParams != "" { 154 | params = append(params, clusterParams) 155 | } 156 | 157 | compParams := renderJsonnet(cmd, params, "", true, "", "clusterparams") 158 | 159 | compString := gjson.Get(compParams, "_components") 160 | err := json.Unmarshal([]byte(compString.String()), &componentMap) 161 | if err != nil { 162 | log.Fatal().Err(err).Msg("failed to parse component map") 163 | } 164 | componentDefaultsMerged := "{" 165 | if len(componentNames) > 0 { 166 | // we are passed a list of components 167 | for _, key := range componentNames { 168 | if value, ok := componentMap[key]; ok { 169 | path := baseDir + "/" + value.Path + "/params.jsonnet" 170 | filec, err := ioutil.ReadFile(path) 171 | if err != nil { 172 | log.Fatal().Err(err).Msg("Error reading " + path) 173 | } 174 | componentDefaultsMerged = componentDefaultsMerged + fmt.Sprintf("'%s': %s,", key, string(filec)) 175 | } 176 | } 177 | } else { 178 | // all components 179 | for key, value := range componentMap { 180 | if componentName != "" && key != componentName { 181 | continue 182 | } 183 | path := baseDir + "/" + value.Path + "/params.jsonnet" 184 | filec, err := ioutil.ReadFile(path) 185 | if err != nil { 186 | log.Fatal().Err(err).Msg("Error reading " + path) 187 | } 188 | componentDefaultsMerged = componentDefaultsMerged + fmt.Sprintf("'%s': %s,", key, string(filec)) 189 | } 190 | } 191 | componentDefaultsMerged = componentDefaultsMerged + "}" 192 | 193 | compParams = renderJsonnet(cmd, params, "", prune, componentDefaultsMerged, "componentparams") 194 | 195 | return compParams 196 | } 197 | -------------------------------------------------------------------------------- /cmd/get.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2019 NAME HERE 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package cmd 16 | 17 | import ( 18 | "github.com/olekukonko/tablewriter" 19 | "github.com/spf13/cobra" 20 | "github.com/tidwall/gjson" 21 | 22 | "fmt" 23 | "os" 24 | 25 | "github.com/rs/zerolog/log" 26 | ) 27 | 28 | // getCmd represents the get command 29 | var getCmd = &cobra.Command{ 30 | Use: "get", 31 | Short: "Display one or many kr8 resources", 32 | Long: `Displays information about kr8 resources such as clusters and components`, 33 | } 34 | 35 | var getclustersCmd = &cobra.Command{ 36 | Use: "clusters", 37 | Short: "Get all clusters", 38 | Long: "Get all clusters defined in kr8 config hierarchy", 39 | Run: func(cmd *cobra.Command, args []string) { 40 | 41 | clusters, err := getClusters(clusterDir) 42 | 43 | if err != nil { 44 | log.Fatal().Err(err).Msg("Error getting cluster") 45 | } 46 | 47 | var entry []string 48 | table := tablewriter.NewWriter(os.Stdout) 49 | table.SetHeader([]string{"Name", "Path"}) 50 | 51 | for _, c := range clusters.Cluster { 52 | entry = append(entry, c.Name) 53 | entry = append(entry, c.Path) 54 | table.Append(entry) 55 | entry = entry[:0] 56 | } 57 | table.Render() 58 | 59 | }, 60 | } 61 | 62 | var getcomponentsCmd = &cobra.Command{ 63 | Use: "components", 64 | Short: "Get all components", 65 | Long: "Get all available components defined in the kr8 config hierarchy", 66 | Run: func(cmd *cobra.Command, args []string) { 67 | 68 | clusterName := cluster 69 | 70 | if clusterName == "" { 71 | log.Fatal().Msg("Please specify a --cluster name") 72 | } 73 | 74 | var params []string 75 | if clusterName != "" { 76 | clusterPath := getCluster(clusterDir, clusterName) 77 | params = getClusterParams(clusterDir, clusterPath) 78 | } 79 | if clusterParams != "" { 80 | params = append(params, clusterParams) 81 | } 82 | 83 | j := renderJsonnet(cmd, params, "._components", true, "", "components") 84 | if paramPath != "" { 85 | value := gjson.Get(j, paramPath) 86 | if value.String() == "" { 87 | log.Fatal().Msg("Error getting param: " + paramPath) 88 | } else { 89 | formatted := Pretty(j, colorOutput) 90 | fmt.Println(formatted) 91 | } 92 | } else { 93 | formatted := Pretty(j, colorOutput) 94 | fmt.Println(formatted) 95 | } 96 | }, 97 | } 98 | 99 | var getparamsCmd = &cobra.Command{ 100 | Use: "params", 101 | Short: "Get parameter for components and clusters", 102 | Long: "Get parameters assigned to clusters and components in the kr8 config hierarchy", 103 | Run: func(cmd *cobra.Command, args []string) { 104 | 105 | clusterName := cluster 106 | 107 | if clusterName == "" { 108 | log.Fatal().Msg("Please specify a --cluster") 109 | } 110 | 111 | fmt.Println(componentName) 112 | 113 | j := renderClusterParams(cmd, clusterName, []string{componentName}, clusterParams, true) 114 | 115 | if paramPath != "" { 116 | value := gjson.Get(j, paramPath) 117 | notunset, _ := cmd.Flags().GetBool("notunset") 118 | if notunset && value.String() == "" { 119 | log.Fatal().Msg("Error getting param: " + paramPath) 120 | } else { 121 | fmt.Println(value) // no formatting because this isn't always json, this is just the value of a field 122 | } 123 | } else { 124 | formatted := Pretty(j, colorOutput) 125 | fmt.Println(formatted) 126 | } 127 | 128 | }, 129 | } 130 | 131 | func init() { 132 | RootCmd.AddCommand(getCmd) 133 | // clusters 134 | getCmd.AddCommand(getclustersCmd) 135 | // components 136 | getCmd.AddCommand(getcomponentsCmd) 137 | getcomponentsCmd.PersistentFlags().StringVarP(&cluster, "cluster", "c", "", "get components for cluster") 138 | // params 139 | getCmd.AddCommand(getparamsCmd) 140 | getparamsCmd.PersistentFlags().StringVarP(&cluster, "cluster", "c", "", "get components for cluster") 141 | getparamsCmd.PersistentFlags().StringVarP(&componentName, "component", "C", "", "component to render params for") 142 | getparamsCmd.Flags().StringVarP(¶mPath, "param", "P", "", "return value of json param from supplied path") 143 | 144 | } 145 | -------------------------------------------------------------------------------- /cmd/init.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Lee Briggs 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package cmd 22 | 23 | import ( 24 | "os" 25 | 26 | "github.com/hashicorp/go-getter" 27 | "github.com/spf13/cobra" 28 | //"github.com/rs/zerolog" 29 | "github.com/rs/zerolog/log" 30 | ) 31 | 32 | var ( 33 | dl_url string 34 | real_url string 35 | ) 36 | 37 | // initCmd represents the init command 38 | var initCmd = &cobra.Command{ 39 | Use: "init", 40 | Short: "Initialize kr8 config repos, components and clusters", 41 | Long: `kr8 requires specific directories and exists for its config to work. 42 | This init command helps in creating directory structure for repos, clusters and 43 | components`, 44 | //Run: func(cmd *cobra.Command, args []string) {}, 45 | } 46 | 47 | var repoCmd = &cobra.Command{ 48 | Use: "repo dir", 49 | Args: cobra.MinimumNArgs(1), 50 | Short: "Initialize a new kr8 config repo", 51 | Long: `Initialize a new kr8 config repo by downloading the kr8 config skeletion repo 52 | and initialize a git repo so you can get started`, 53 | Run: func(cmd *cobra.Command, args []string) { 54 | 55 | if len(args) < 1 { 56 | log.Fatal().Msg("Must specify a destination") 57 | } 58 | 59 | if dl_url != "" { 60 | real_url = dl_url 61 | } else { 62 | log.Fatal().Msg("Must specify a URL") 63 | } 64 | // Get the current working directory 65 | pwd, err := os.Getwd() 66 | if err != nil { 67 | log.Fatal().Err(err).Msg("Error getting working directory") 68 | } 69 | 70 | // Download the skeletion directory 71 | log.Debug().Msg("Downloading skeleton repo from " + real_url) 72 | client := &getter.Client{ 73 | Src: real_url, 74 | Dst: args[0], 75 | Pwd: pwd, 76 | Mode: getter.ClientModeAny, 77 | } 78 | 79 | if err := client.Get(); err != nil { 80 | log.Fatal().Err(err).Msg("") 81 | os.Exit(1) 82 | } 83 | 84 | // Check for .git folder 85 | if _, err := os.Stat(args[0] + "/.git"); !os.IsNotExist(err) { 86 | log.Debug().Msg("Removing .git directory") 87 | os.RemoveAll(args[0] + "/.git") 88 | } 89 | }, 90 | } 91 | 92 | func init() { 93 | RootCmd.AddCommand(initCmd) 94 | initCmd.AddCommand(repoCmd) 95 | 96 | repoCmd.PersistentFlags().StringVar(&dl_url, "url", "git::https://github.com/apptio/kr8-config-skel", "Source of skeleton directory to create repo from") 97 | 98 | } 99 | -------------------------------------------------------------------------------- /cmd/json.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/fatih/color" 5 | "github.com/hokaccha/go-prettyjson" 6 | "github.com/rs/zerolog/log" 7 | ) 8 | 9 | func Pretty(input string, colorOutput bool) string { 10 | 11 | f := prettyjson.NewFormatter() 12 | f.Indent = 4 13 | if !colorOutput { 14 | f.DisabledColor = true 15 | } 16 | f.KeyColor = color.New(color.FgRed) 17 | f.NullColor = color.New(color.Underline) 18 | 19 | formatted, err := f.Format([]byte(input)) 20 | 21 | if err != nil { 22 | log.Fatal().Err(err).Msg("Error formatting JSON") 23 | } 24 | 25 | return string(formatted) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /cmd/render.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | goyaml "github.com/ghodss/yaml" 5 | "github.com/spf13/cobra" 6 | 7 | "bufio" 8 | "fmt" 9 | "io" 10 | "os" 11 | 12 | "github.com/rs/zerolog/log" 13 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 | "k8s.io/apimachinery/pkg/util/yaml" 15 | ) 16 | 17 | var renderCmd = &cobra.Command{ 18 | Use: "render", 19 | Short: "Render files", 20 | Long: `Render files in jsonnet or UAML`, 21 | } 22 | 23 | var renderjsonnetCmd = &cobra.Command{ 24 | Use: "jsonnet file [file ...]", 25 | Short: "Render a jsonnet file", 26 | Long: `Render a jsonnet file to JSON or YAML`, 27 | 28 | Args: cobra.MinimumNArgs(1), 29 | Run: func(cmd *cobra.Command, args []string) { 30 | jsonnetrenderCmd.Run(cmd, args) 31 | }, 32 | } 33 | 34 | var helmcleanCmd = &cobra.Command{ 35 | Use: "helmclean", 36 | Short: "Clean YAML stream from Helm Template output - Reads from Stdin", 37 | Long: `Removes Null YAML objects from a YAML stream`, 38 | Run: func(cmd *cobra.Command, args []string) { 39 | decoder := yaml.NewYAMLReader(bufio.NewReader(os.Stdin)) 40 | jsa := [][]byte{} 41 | for { 42 | bytes, err := decoder.Read() 43 | if err == io.EOF { 44 | break 45 | } else if err != nil { 46 | log.Fatal().Err(err).Msg("Error decoding decoding yaml stream") 47 | } 48 | if len(bytes) == 0 { 49 | continue 50 | } 51 | jsondata, err := yaml.ToJSON(bytes) 52 | if err != nil { 53 | log.Fatal().Err(err).Msg("Error encoding yaml to JSON") 54 | } 55 | if string(jsondata) == "null" { 56 | // skip empty json 57 | continue 58 | } 59 | _, _, err = unstructured.UnstructuredJSONScheme.Decode(jsondata, nil, nil) 60 | if err != nil { 61 | log.Fatal().Err(err).Msg("Error handling unstructured JSON") 62 | } 63 | jsa = append(jsa, jsondata) 64 | } 65 | for _, j := range jsa { 66 | out, err := goyaml.JSONToYAML(j) 67 | if err != nil { 68 | log.Fatal().Err(err).Msg("Error encoding JSON to YAML") 69 | } 70 | fmt.Println("---") 71 | fmt.Println(string(out)) 72 | } 73 | }, 74 | } 75 | 76 | func init() { 77 | RootCmd.AddCommand(renderCmd) 78 | renderCmd.AddCommand(renderjsonnetCmd) 79 | renderjsonnetCmd.PersistentFlags().BoolVarP(&pruneFlag, "prune", "", true, "Prune null and empty objects from rendered json") 80 | renderjsonnetCmd.PersistentFlags().StringVarP(&clusterParams, "clusterparams", "", "", "provide cluster params as single file - can be combined with --cluster to override cluster") 81 | renderjsonnetCmd.PersistentFlags().StringVarP(&componentName, "component", "C", "", "component to render params for") 82 | renderjsonnetCmd.PersistentFlags().StringVarP(&outputFormat, "format", "F", "json", "Output forma: json, yaml, stream") 83 | renderjsonnetCmd.PersistentFlags().StringVarP(&cluster, "cluster", "c", "", "cluster to render params for") 84 | renderCmd.AddCommand(helmcleanCmd) 85 | } 86 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Lee Briggs 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package cmd 22 | 23 | import ( 24 | "fmt" 25 | "os" 26 | 27 | "github.com/spf13/cobra" 28 | "github.com/spf13/viper" 29 | 30 | "github.com/rs/zerolog" 31 | "github.com/rs/zerolog/log" 32 | ) 33 | 34 | var ( 35 | cfgFile string 36 | baseDir string 37 | clusterDir string 38 | componentDir string 39 | clusterParams string 40 | cluster string 41 | logLevel string 42 | 43 | debug bool 44 | colorOutput bool 45 | ) 46 | 47 | // exported Version variable 48 | var Version string 49 | 50 | // RootCmd represents the base command when called without any subcommands 51 | var RootCmd = &cobra.Command{ 52 | Use: "kr8", 53 | Short: "Kubernetes config parameter framework", 54 | Long: `A tool to generate Kubernetes configuration from a hierarchy 55 | of jsonnet files`, 56 | } 57 | 58 | // Execute adds all child commands to the root command sets flags appropriately. 59 | // This is called by main.main(). It only needs to happen once to the rootCmd. 60 | func Execute(version string) { 61 | Version = version 62 | if err := RootCmd.Execute(); err != nil { 63 | fmt.Println(err) 64 | os.Exit(-1) 65 | } 66 | } 67 | 68 | func init() { 69 | cobra.OnInitialize(initConfig) 70 | 71 | RootCmd.PersistentFlags().StringVarP(&baseDir, "base", "d", ".", "kr8 config base directory") 72 | RootCmd.PersistentFlags().StringVarP(&clusterDir, "clusterdir", "D", "", "kr8 cluster directory") 73 | RootCmd.PersistentFlags().StringVarP(&componentDir, "componentdir", "X", "", "kr8 component directory") 74 | RootCmd.PersistentFlags().StringVarP(&logLevel, "loglevel", "L", "info", "set log level") 75 | RootCmd.PersistentFlags().BoolVar(&debug, "debug", false, "log more information about what kr8 is doing. Overrides --loglevel") 76 | RootCmd.PersistentFlags().BoolVar(&colorOutput, "color", true, "enable colorized output (default). Set to false to disable") 77 | RootCmd.PersistentFlags().StringArrayP("jpath", "J", nil, "Directories to add to jsonnet include path. Repeat arg for multiple directories") 78 | RootCmd.PersistentFlags().StringSlice("ext-str-file", nil, "Set jsonnet extvar from file contents") 79 | viper.BindPFlag("base", RootCmd.PersistentFlags().Lookup("base")) 80 | viper.BindPFlag("clusterdir", RootCmd.PersistentFlags().Lookup("clusterdir")) 81 | viper.BindPFlag("componentdir", RootCmd.PersistentFlags().Lookup("componentdir")) 82 | viper.BindPFlag("color", RootCmd.PersistentFlags().Lookup("color")) 83 | } 84 | 85 | // initConfig reads in config file and ENV variables if set. 86 | func initConfig() { 87 | if cfgFile != "" { // enable ability to specify config file via flag 88 | viper.SetConfigFile(cfgFile) 89 | } 90 | 91 | if debug { 92 | zerolog.SetGlobalLevel(zerolog.DebugLevel) 93 | } else { 94 | switch logLevel { 95 | case "debug": 96 | zerolog.SetGlobalLevel(zerolog.DebugLevel) 97 | case "info": 98 | zerolog.SetGlobalLevel(zerolog.InfoLevel) 99 | case "warn": 100 | zerolog.SetGlobalLevel(zerolog.WarnLevel) 101 | case "error": 102 | zerolog.SetGlobalLevel(zerolog.ErrorLevel) 103 | case "fatal": 104 | zerolog.SetGlobalLevel(zerolog.FatalLevel) 105 | case "panic": 106 | zerolog.SetGlobalLevel(zerolog.PanicLevel) 107 | default: 108 | log.Fatal().Msg("invalid log level: " + logLevel) 109 | } 110 | } 111 | 112 | viper.SetConfigName(".kr8") // name of config file (without extension) 113 | viper.AddConfigPath(".") 114 | viper.AddConfigPath("$HOME") // adding home directory as first search path 115 | viper.SetEnvPrefix("KR8") 116 | viper.AutomaticEnv() // read in environment variables that match 117 | 118 | // If a config file is found, read it in. 119 | if err := viper.ReadInConfig(); err == nil { 120 | log.Debug().Msg("Using config file:" + viper.ConfigFileUsed()) 121 | } 122 | colorOutput = viper.GetBool("color") 123 | log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, NoColor: !colorOutput}) 124 | 125 | baseDir = viper.GetString("base") 126 | log.Debug().Msg("Using base directory: " + baseDir) 127 | clusterDir = viper.GetString("clusterdir") 128 | if clusterDir == "" { 129 | clusterDir = baseDir + "/clusters" 130 | } 131 | log.Debug().Msg("Using cluster directory: " + clusterDir) 132 | if componentDir == "" { 133 | componentDir = baseDir + "/components" 134 | } 135 | log.Debug().Msg("Using component directory: " + componentDir) 136 | 137 | } 138 | -------------------------------------------------------------------------------- /cmd/types.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | // init a struct for a single item 4 | type Cluster struct { 5 | Name string 6 | Path string 7 | } 8 | 9 | // init a grouping struct 10 | type Clusters struct { 11 | Cluster []Cluster 12 | } 13 | -------------------------------------------------------------------------------- /cmd/vars.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | var ( 4 | componentName string 5 | paramPath string 6 | ) 7 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Lee Briggs 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package cmd 22 | 23 | import ( 24 | "fmt" 25 | 26 | "github.com/spf13/cobra" 27 | ) 28 | 29 | // versionCmd represents the version command 30 | var versionCmd = &cobra.Command{ 31 | Use: "version", 32 | Short: "Return the current version of kr8", 33 | Long: `return the current version of kr8`, 34 | Run: func(cmd *cobra.Command, args []string) { 35 | fmt.Println(RootCmd.Use + " " + Version) 36 | }, 37 | } 38 | 39 | func init() { 40 | RootCmd.AddCommand(versionCmd) 41 | } 42 | -------------------------------------------------------------------------------- /cmd/yaml.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Lee Briggs 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package cmd 22 | 23 | import ( 24 | "bufio" 25 | "fmt" 26 | gyaml "github.com/ghodss/yaml" 27 | "github.com/rs/zerolog/log" 28 | "github.com/spf13/cobra" 29 | "io" 30 | "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 31 | "k8s.io/apimachinery/pkg/util/yaml" 32 | "os" 33 | ) 34 | 35 | var yamlCmd = &cobra.Command{ 36 | Use: "yaml", 37 | Short: "YAML utilities", 38 | Long: `Utility commands to process YAML`, 39 | } 40 | 41 | var yamlhelmcleanCmd = &cobra.Command{ 42 | Use: "helmclean", 43 | Short: "Clean YAML stream from Helm Template output - Reads from Stdin", 44 | Long: `Removes Null YAML objects from a YAML stream`, 45 | Run: func(cmd *cobra.Command, args []string) { 46 | decoder := yaml.NewYAMLReader(bufio.NewReader(os.Stdin)) 47 | jsa := [][]byte{} 48 | for { 49 | bytes, err := decoder.Read() 50 | if err == io.EOF { 51 | break 52 | } else if err != nil { 53 | log.Fatal().Err(err).Msg("Error decoding decoding yaml stream") 54 | } 55 | if len(bytes) == 0 { 56 | continue 57 | } 58 | jsondata, err := yaml.ToJSON(bytes) 59 | if err != nil { 60 | log.Fatal().Err(err).Msg("Error encoding yaml to JSON") 61 | } 62 | if string(jsondata) == "null" { 63 | // skip empty json 64 | continue 65 | } 66 | _, _, err = unstructured.UnstructuredJSONScheme.Decode(jsondata, nil, nil) 67 | if err != nil { 68 | log.Fatal().Err(err).Msg("Error handling unstructured JSON") 69 | } 70 | jsa = append(jsa, jsondata) 71 | } 72 | for _, j := range jsa { 73 | out, err := gyaml.JSONToYAML(j) 74 | if err != nil { 75 | log.Fatal().Err(err).Msg("Error encoding JSON to YAML") 76 | } 77 | fmt.Println("---") 78 | fmt.Println(string(out)) 79 | } 80 | }, 81 | } 82 | 83 | func init() { 84 | RootCmd.AddCommand(yamlCmd) 85 | yamlCmd.AddCommand(yamlhelmcleanCmd) 86 | 87 | } 88 | -------------------------------------------------------------------------------- /docs/building.md: -------------------------------------------------------------------------------- 1 | # Building kr8 2 | 3 | As mentioned before, kr8 is coded in [Golang](https://golang.org/) so after following the next steps you should be able to use the kr8 executable like this: 4 | 5 | `./kr8 --help` 6 | 7 | ## Prerequisites 8 | 9 | 1. Install and configure Go: https://golang.org/doc/install 10 | 11 | 2. Get familiar with Golang: https://golang.org/doc/ 12 | 13 | 3. If you are fully testing the build you need to install: https://github.com/go-task/task 14 | 15 | ---- 16 | 17 | ## Building the executable 18 | 19 | On the project root: 20 | 21 | `go build` 22 | 23 | Go will start downloading the dependencies to create the executable, then you will end up with the following file: 24 | 25 | `-rwxr-xr-x 1 myuser mygroup 23M Apr 2 12:44 kr8` 26 | 27 | Where `23M` is the current size of the executable. 28 | 29 | ## Troubleshooting the process 30 | 31 | 1. Dependencies download fail: 32 | There is a big number of reasons this could fail but the most important might be: 33 | -Networking problems: Check your connection to: github.com, golang.org and k8s.io. 34 | -Disk space: If no space is available on the disk, this step might fail. 35 | 36 | 2. The comand `go build` does not start the build: 37 | -Confirm you are in the correct project directory. 38 | -Make sure your go installation works: `go` 39 | 40 | ---- 41 | -------------------------------------------------------------------------------- /docs/components/helm.md: -------------------------------------------------------------------------------- 1 | # Helm 2 | 3 | kr8 can render helm charts locally and inject parameters as helm values. This provides a great degree of flexibility when installing components into clusters. 4 | 5 | ## Taskfile 6 | 7 | An example taskfile for a helm chart might look like this: 8 | 9 | ```yaml 10 | version: 2 11 | 12 | vars: 13 | CHART_VER: v0.8.1 14 | CHART_NAME: cert-manager 15 | 16 | tasks: 17 | fetch: 18 | desc: "fetch component dependencies" 19 | cmds: 20 | - rm -fr charts vendored; mkdir charts vendored 21 | # add the helm repo and fetch it locally into the charts directly 22 | - helm fetch --repo https://charts.jetstack.io --untar --untardir ./charts --version "{{.CHART_VER}}" "{{.CHART_NAME}}" 23 | - wget --quiet -N https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml -O - | grep -v ^# > vendored/00cert-manager-crd.yaml 24 | 25 | 26 | generate: 27 | desc: "generate" 28 | cmds: 29 | - kr8-helpers clean-output 30 | - kr8-helpers yaml-install vendored/00cert-manager-crd.yaml 31 | - kr8-helpers jsonnet-render 00namespace.jsonnet 32 | - kr8-helpers helm-render "{{.CHART_NAME}}" 33 | ``` 34 | 35 | ## Params 36 | 37 | The `params.jsonnet` for a helm chart directory should include the helm values you want to use. Here's an example: 38 | 39 | ```jsonnet 40 | { 41 | release_name: 'cert-manager', 42 | namespace: 'cert-manager', 43 | kubecfg_gc_enable: true, 44 | kubecfg_update_args: '--validate=false', 45 | helm_values: { 46 | webhook: { enabled: false }, // this is a value for the helm chart 47 | }, 48 | } 49 | ``` 50 | 51 | ## Values file 52 | 53 | A values file is a required file for a helm component. The name of the file must be `componentname-values.jsonnet` (for example: cert-manager-values.jsonnet). It's content would be something like this: 54 | 55 | ```jsonnet 56 | local config = std.extVar('kr8'); 57 | 58 | if 'helm_values' in config then config.helm_values else {} 59 | ``` 60 | 61 | You can also optionally set the values for the helm chart in here, this would look something like this: 62 | 63 | ```jsonnet 64 | { 65 | replicaCount: 2 66 | } 67 | ``` 68 | 69 | ## Patches 70 | 71 | There are certain situations where a configuration option is not available for a helm chart, for example, you might want to add an argument that hasn't quite made it into the helm chart yet, or add something like [pod affinity](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity) where it isn't actually a value option in a helm chart. 72 | 73 | kr8 helps you in this situation by providing a mechanism to patch a helm chart. You need to use the `helm-render-with-patch` helper and provide a `patches.jsonnet` in the component directory. 74 | 75 | Here's an example `patches.jsonnet` for [external-dns](https://github.com/kubernetes-incubator/external-dns) 76 | 77 | ```jsonnet 78 | local apptio = import 'apptio.libsonnet'; 79 | local helpers = import 'helpers.libsonnet'; // some helper functions 80 | local kube = import 'kube.libsonnet'; 81 | local config = std.extVar('kr8'); // config is all the config from params.jsonnet 82 | 83 | // remove Secret objects and add a namespace 84 | [ 85 | for object in helpers.list( 86 | // object list is converted to hash of named objects, then they can be modified by name 87 | helpers.named(helpers.helmInput) + { 88 | ['Deployment/' + config.release_name]+: helpers.patchContainer({ 89 | // Injects an extra arg, which wasn't originally in the helm chart 90 | [if std.objectHas(config,'assumeRoleArn') then 'args']+: ['--aws-assume-role='+config.assumeRoleArn], 91 | }), 92 | }, 93 | ) 94 | ] 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/components/jk.md: -------------------------------------------------------------------------------- 1 | # jk 2 | -------------------------------------------------------------------------------- /docs/components/jsonnet.md: -------------------------------------------------------------------------------- 1 | # Jsonnet Component 2 | 3 | A very simple component might just be a few lines of jsonnet. 4 | 5 | Consider the situation whereby you might have two clusters, one in AWS and one in DigitalOcean. You need to set a default storageclass. You could do this with jsonnet. 6 | 7 | Your jsonnet component would look like this: 8 | 9 | ```bash 10 | components/storageclasses 11 | ├── Taskfile.yml 12 | ├── params.jsonnet 13 | ├── storageclasses.jsonnet 14 | ``` 15 | 16 | ## Taskfile 17 | 18 | The taskfile for a component like would look like this: 19 | 20 | ```yaml 21 | version: 2 22 | 23 | tasks: 24 | fetch: 25 | desc: "fetch component dependencies" 26 | 27 | generate: 28 | desc: "generate" 29 | cmds: 30 | - kr8-helpers clean-output 31 | - kr8-helpers jsonnet-render storageclasses.jsonnet 32 | ``` 33 | 34 | Notice we still add a fetch task which is an empty command 35 | 36 | ## Params 37 | 38 | As a reminder, every component requires a params file. We need to set a namespace for the component, even though it's a cluster level resource - namespace is a required paramater for kr8 39 | 40 | ```yaml 41 | { 42 | namespace: 'kube-system', 43 | release_name: 'storageclasses', 44 | } 45 | ``` 46 | 47 | ## Jsonnet Manifest 48 | 49 | Your jsonnet manifest looks like this: 50 | 51 | ```jsonnet 52 | local config = std.extVar('kr8'); # imports the config from params.jsonnet 53 | local kr8_cluster = std.extVar('kr8_cluster'); # a jsonnet external variable from kr8 that gets cluster values and data 54 | 55 | # a jsonnet function for creating a storageclass 56 | local StorageClass(name, type, default=false) = { 57 | apiVersion: 'storage.k8s.io/v1', 58 | kind: 'StorageClass', 59 | metadata: { 60 | name: name, 61 | annotations: { 62 | 'storageclass.kubernetes.io/is-default-class': if default then 'true' else 'false', 63 | }, 64 | }, 65 | parameters: { 66 | type: type, 67 | }, 68 | }; 69 | 70 | # check the cluster configuration for a type, if it's AWS make a gp2 type storageclass 71 | if kr8_cluster.cluster_type == 'aws' then kube.objectValues( 72 | { 73 | // default gp2 storage class, not tied to a zone 74 | ebs_gp2: StorageClass('gp2', 'gp2', true) {}, 75 | } 76 | ) else [] # don't make a storageclass if it's not AWS 77 | ``` 78 | 79 | 80 | -------------------------------------------------------------------------------- /docs/components/yaml.md: -------------------------------------------------------------------------------- 1 | # YAML Component 2 | 3 | kr8 can use a static k8s manifest as a source input. You can then manipulate the structure of that YAML using Jsonnet. kr8 takes care of the heavy lifting for you. 4 | 5 | ## Taskfile 6 | 7 | You'll need a taskfile that downloads the original manifests for you in the `fetch` task. Here's an example: 8 | 9 | ```yaml 10 | 11 | version: 2 12 | 13 | # Download the example manifests for the metrics server. 14 | # This creates a directory, "vendored" which contains the manifests 15 | tasks: 16 | fetch: 17 | desc: "fetch component dependencies" 18 | cmds: 19 | - rm -rf vendored 20 | - mkdir -p vendored sources 21 | - git clone --depth=1 https://github.com/kubernetes-incubator/metrics-server sources/metrics-server 22 | - cp -a sources/metrics-server/deploy/1.8+/*.yaml ./vendored/ 23 | - git add ./vendored 24 | - rm -rf sources 25 | 26 | generate: 27 | desc: "generate" 28 | cmds: 29 | - kr8-helpers clean-output 30 | - find vendored -type f -name "*.yaml" -exec kr8-helpers yaml-install '{}' \; # install all the manifests in the vendored directory directly, without changing then 31 | # use the metrics-server-deployment.yaml as the input to the jsonnet file 32 | - KR8_JSONNET_ARGS='--ext-str-file inputMetricsServerDeploy=vendored/metrics-server-deployment.yaml' kr8-helpers jsonnet-render metrics-server-deployment.jsonnet 33 | ``` 34 | 35 | ## Jsonnet 36 | 37 | You'll notice in the taskfile above that this line: 38 | 39 | ``` 40 | KR8_JSONNET_ARGS='--ext-str-file inputMetricsServerDeploy=vendored/metrics-server-deployment.yaml' kr8-helpers jsonnet-render metrics-server-deployment.jsonnet 41 | ``` 42 | 43 | References one of the files in vendored. This give us the ability to modify this file. Here's how the jsonnet looks: 44 | 45 | ```jsonnet 46 | local helpers = import 'helpers.libsonnet'; 47 | local parseYaml = std.native('parseYaml'); 48 | # this must match the `ext-str-file` value in the taskfile 49 | # it imports those values with the variable name "deployment" 50 | local deployment = parseYaml(std.extVar('inputMetricsServerDeploy')); 51 | 52 | local args = [ 53 | "--kubelet-insecure-tls", 54 | "--kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname", 55 | ] 56 | 57 | [ 58 | # drop all the secrets if they're found, we don't want to check them into git 59 | if object.kind == 'Secret' then {} else object 60 | for object in helpers.list( 61 | helpers.named(deployment) + { 62 | # grab kind deployment with name metrics-server, and add some more args 63 | ['Deployment/kube-system/metrics-server']+: helpers.patchContainerNamed( 64 | "metrics-server", 65 | { 66 | "args"+: args, 67 | } 68 | ), 69 | } 70 | ) 71 | ] 72 | 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/concepts/clusters.md: -------------------------------------------------------------------------------- 1 | # Clusters 2 | 3 | A cluster is a manageable cluster in kr8. Clusters are defined in a hierarchical system which is loosely inspired by [Hiera](https://puppet.com/docs/hiera/3.3/index.html) from the Puppet ecosystem. 4 | 5 | An example definition for clusters might look like this: 6 | 7 | ```bash 8 | clusters 9 | ├── development 10 | │   └── dev1 11 | │   └── cluster.jsonnet 12 | ├── params.jsonnet 13 | └── production 14 | ├── params.jsonnet 15 | ├── prod1 16 | │   └── cluster.jsonnet 17 | └── prod2 18 | └── cluster.jsonnet 19 | ``` 20 | 21 | The clusters are given names and then grouped together inside a directory tree. 22 | 23 | There are two jsonnet files you'll notice here: 24 | 25 | - `cluster.jsonnet` - this defines a named cluster, kr8 will stop going down through the directory tree when it finds this file 26 | - `params.jsonnet` - this is a file which can have components and parameters defined for clustes lower down in the hierarchy. We'll go into more detail about this shortly. 27 | 28 | ## Components in clusters 29 | 30 | Adding a component to a cluster involves add a component key to the `_components` key inside _either_ the `cluster.jsonnet` or the `params.jsonnet`. 31 | 32 | Here's an example: 33 | 34 | ```jsonnet 35 | _components+: { 36 | sealed_secrets: { path: 'components/sealed_secrets' }, 37 | }, 38 | ``` 39 | 40 | Notice we're using the jsonnet `+` operator to make sure we're appending this to the list of components for that cluster, which will ensure the inheritance system works 41 | 42 | ## Cluster parameters 43 | 44 | Once you've initialized a component for a cluster, you can then start to override parameters for that component. You do this by simply defining a jsonnet key with the named parameters in it. Here's an example: 45 | 46 | ```jsonnet 47 | external_dns+: { 48 | provider: 'cloudflare', 49 | txtPrefix: 'dev1', 50 | txtOwnerId: 'dev1-', 51 | domainFilters: [ 52 | 'example.com', 53 | ], 54 | tolerateMasters: false, 55 | }, 56 | ``` 57 | 58 | ## Hierarchy System 59 | 60 | The hierarchy system is a very powerful part or kr8. It allows you to remove duplication of parameter and component definitions. Take the previous cluster layout as an example: 61 | 62 | ``` 63 | clusters 64 | ├── development 65 | │   └── dev1 66 | │   └── cluster.jsonnet 67 | ├── params.jsonnet 68 | └── production 69 | ├── params.jsonnet 70 | ├── prod1 71 | │   └── cluster.jsonnet 72 | └── prod2 73 | └── cluster.jsonnet 74 | ``` 75 | 76 | You can use the hierarchy system to ensure you have components installed in all clusters. Let's assume we want to make sure that we want to install the `sealed_secrets` component in _all_ our clusters. We'd put it in this file: 77 | 78 | ``` 79 | clusters 80 | ├── development 81 | │   └── dev1 82 | │   └── cluster.jsonnet 83 | ├── params.jsonnet <---- place component here 84 | └── production 85 | ├── params.jsonnet 86 | ├── prod1 87 | │   └── cluster.jsonnet 88 | └── prod2 89 | └── cluster.jsonnet 90 | ``` 91 | 92 | Alongside that, let's assume all our production clusters are using the same external_dns domain name. We can define that like so: 93 | 94 | ``` 95 | clusters 96 | ├── development 97 | │   └── dev1 98 | │   └── cluster.jsonnet 99 | ├── params.jsonnet 100 | └── production 101 | ├── params.jsonnet <--- place external_dns configuration here 102 | ├── prod1 103 | │   └── cluster.jsonnet 104 | └── prod2 105 | └── cluster.jsonnet 106 | ``` 107 | 108 | kr8 will look for the smallest unit of configuration, so if you want one cluster to be slightly different inside a hierarchy unit, you can continue to override components and parameters inside a clusters' `cluster.jsonnet` file. 109 | 110 | 111 | -------------------------------------------------------------------------------- /docs/concepts/components.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | A component is a deployable unit that you wish to install to multiple clusters. 4 | 5 | Your component might begin life before kr8 in one of a few ways: 6 | 7 | - a [Helm Chart](https://github.com/helm/charts/tree/master/stable) 8 | - a static [YAML manifest](https://github.com/kubernetes/examples/blob/master/guestbook/all-in-one/guestbook-all-in-one.yaml) 9 | - some [Jsonnet](https://github.com/coreos/prometheus-operator/tree/master/jsonnet/prometheus-operator) 10 | 11 | but they all have something in common - you need to deploy it to multiple clusters with slight differences in configuration. 12 | 13 | 14 | ## Taskfile 15 | 16 | This task file lives inside the component directory. It should contain two tasks: 17 | 18 | - fetch - a manually run task which downloads all the components' dependencies (for example, helm chart or static manifest) 19 | - generate - this is the task that's run when kr8 generates the manifest for the cluster 20 | 21 | 22 | These tasks will be highly dependent on the particular component - for example, a component using a helm chart will generally have a different set of fetch and generate tasks to a component using a static manifest. 23 | 24 | An example Taskfile might look like this: 25 | 26 | ```yaml 27 | version: 2 28 | 29 | vars: 30 | KR8_COMPONENT: kubemonkey 31 | 32 | tasks: 33 | fetch: 34 | desc: "fetch component kubemonkey" 35 | cmds: 36 | - curl -L https://github.com/asobti/kube-monkey/tarball/master > kubemonkey.tar.gz # download the local helm chart from the git repo 37 | - tar --strip-components=2 -xzvf kubemonkey.tar.gz asobti-kube-monkey-{{.GIT_COMMIT}}/helm # extract it 38 | - mv kubemonkey charts # place it in a charts directory 39 | - rm -fr *.tar.gz # remove the tar.gz from the repo 40 | vars: 41 | GIT_COMMIT: 42 | sh: curl -s https://api.github.com/repos/asobti/kube-monkey/commits/master | jq .sha -r | xargs git rev-parse --short 43 | 44 | generate: 45 | desc: "generate" 46 | cmds: 47 | - KR8_COMPONENT={{.KR8_COMPONENT}} kr8-helpers clean-output # clean the tmp directories each time we generate 48 | - KR8_COMPONENT={{.KR8_COMPONENT}} kr8-helpers helm-render-with-patch "{{.KR8_COMPONENT}}" patches.jsonnet # our generate command, which in this case is a helm-render with some patches in a jsonnet file 49 | ``` 50 | 51 | ## Params 52 | 53 | kr8's most useful feature is the ability to configure _parameters_ for a specific cluster. It does that by specifying a `params.jsonnet` in each component. 54 | 55 | There are some *required* parameters which always must exist. They are: 56 | 57 | - `namespace`: the namespace the component should be installed in 58 | - `release_name`: analogous to a helm release - what the component should be called when it's installed into a cluster 59 | - `kubecfg_gc_enable`: whether this component should be garbage collected when the deployer script cleans up this component (generally should be false for important system components like namespaces) 60 | 61 | 62 | Without these parameters, components will not install a function. A barebones `params.jsonnet` would look like this: 63 | 64 | ```jsonnet 65 | { 66 | namespace: 'kubemonkey', 67 | release_name: 'kubemonkey', 68 | kubecfg_gc_enable: true, 69 | } 70 | ``` 71 | 72 | ### Cluster specific parameters 73 | 74 | Once you start to install components into clusters, you'll want to specify parameters of your own. 75 | 76 | These are done in the `params.jsonnet` and you can either specify a default, or make it mandatory using jsonnet's `error`. 77 | 78 | Here's an more detailed example: 79 | 80 | ```jsonnet 81 | { 82 | namespace: 'kubemonkey', 83 | release_name: 'kubemonkey', 84 | kubecfg_gc_enable: true, 85 | dry_run: false, 86 | run_hour: error 'Must specify a time for kubemonkey to run' 87 | } 88 | ``` 89 | 90 | -------------------------------------------------------------------------------- /docs/concepts/helpers.md: -------------------------------------------------------------------------------- 1 | # Helpers 2 | 3 | kr8-helpers is a set of scripts that wraps around the kr8 command for rendering components. The different types of components have different helps. 4 | 5 | You should ensure the `kr8-helpers` scripts are available in your `$PATH`. You can find them [here](https://github.com/apptio/kr8/tree/master/scripts) 6 | 7 | ## clean-output 8 | 9 | This helper cleans the generated directory and the metadata directory for each component. It should generally be the first helper you run as part of your component Taskfile 10 | 11 | ## helm-render 12 | 13 | Render a helm chart using `helm template`. This allows you to install helm charts as components with kr8. For more information, see the [helm component section](../components/helm.md) 14 | 15 | Example: 16 | 17 | ```bash 18 | kr8-helpers helm-render "{{.CHART_NAME}}" 19 | ``` 20 | 21 | ## helm-render-with-patch 22 | 23 | Similar to `helm-render` except you can also patch the helm chart and add options and configuration that might not be exposed as a helm `values.yaml`. This helper will look for a `patches.jsonnet` inside the component directory. For more information, see the [helm component section](../components/helm.md) 24 | 25 | Example: 26 | 27 | ```bash 28 | kr8-helpers helm-render-with-patch "{{.CHART_NAME}}" patches.jsonnet 29 | ``` 30 | 31 | ## yaml-install 32 | 33 | The simplest helper, this just copies a specified yaml file for the component into the generated directory. It also cleans the yaml file of any unnecessary whitespace using the `helmclean` command in kr8 34 | 35 | Example: 36 | 37 | ```bash 38 | kr8-helpers yaml-install vendored/01_crd.yaml 39 | ``` 40 | 41 | ## jsonnet-render 42 | 43 | Render a jsonnet file. If you're starting a component without any source manifests or helm chart, or using something like the [prometheus-operator](https://github.com/coreos/prometheus-operator/tree/master/jsonnet/prometheus-operator) this would be what you'd use. 44 | 45 | Example: 46 | 47 | ```bash 48 | kr8-helpers jsonnet-render secrets.jsonnet 49 | ``` 50 | 51 | ## jk-render 52 | 53 | [jk](https://jkcfg.github.io/#/) is a tool which allows you to write configuration as actual code. You can use `jk` to render a component: 54 | 55 | Example: 56 | 57 | ```bash 58 | kr8-helpers jk-render nginx.js 59 | ``` 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/concepts/overview.md: -------------------------------------------------------------------------------- 1 | # Concepts 2 | 3 | kr8 has two main concepts you should be aware of before you get started: 4 | 5 | - [components](components.md) 6 | - [clusters](clusters.md) 7 | 8 | The relationship between components and clusters are simple: components are installed on clusters. You will have components that are installed on all clusters, and some components will only be installed on _some_ clusters. 9 | 10 | Components can be declared multiple times within a cluster, as long as they are named distinctly. 11 | 12 | Clusters are unique and singular. They have a name which is specified via the directory structure under `clusters` 13 | 14 | Read more about [components](components.md) and [clusters](clusters.md) 15 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # kr8 2 | 3 | kr8 is a configuration management tool for Kubernetes clusters, designed to generate deployable manifests for the components required to make your clusters usable. 4 | 5 | Its main function is to manipulate JSON and YAML without using a templating engine. It does this using [jsonnet](http://jsonnet.org) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/installation/dependencies.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | 3 | The kr8 binary has a single job: generate manifests. In order to ensure you can create components and install them, you'll need some dependencies. 4 | 5 | ## go-task 6 | 7 | Each component in a kr8 configuration directory must have a [Taskfile](https://taskfile.org). To generate the component, you'll need to install go-task. 8 | 9 | See the [go-task installation instructions](https://github.com/go-task/task/blob/master/docs/installation.md) for more information 10 | -------------------------------------------------------------------------------- /docs/installation/linux.md: -------------------------------------------------------------------------------- 1 | # Linux 2 | 3 | kr8 is a Go binary, which means you can simply download it from the [Github releases page](https://github.com/apptio/kr8/releases) 4 | 5 | RPM and DEB packages are also generated for each release 6 | 7 | ## Dependencies 8 | 9 | Installation with Linux does not pull in the additional dependencies. Please see the [dependencies](dependencies.md) page for more details. 10 | -------------------------------------------------------------------------------- /docs/installation/osx.md: -------------------------------------------------------------------------------- 1 | # OS X 2 | 3 | ## Homebrew 4 | 5 | The easiest way to get started with kr8 is to use the homebrew tap. This will install all the tools kr8 depends on for you. 6 | 7 | ```bash 8 | brew tap apptio/tap 9 | brew install kr8 10 | ``` 11 | 12 | ## Manually 13 | 14 | kr8 is a Go binary, which means you can simply download it from the [Github releases page](https://github.com/apptio/kr8/releases) 15 | 16 | If you choose to install kr8 manually, you'll need to install the dependencies. Please see the [dependencies](dependencies.md) page for more details 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/apptio/kr8 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/fatih/color v1.17.0 7 | github.com/ghodss/yaml v1.0.0 8 | github.com/google/go-jsonnet v0.20.0 9 | github.com/grafana/tanka v0.27.1 10 | github.com/hashicorp/go-getter v1.7.4 11 | github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f 12 | github.com/olekukonko/tablewriter v0.0.5 13 | github.com/panjf2000/ants/v2 v2.10.0 14 | github.com/rs/zerolog v1.33.0 15 | github.com/spf13/cobra v1.8.1 16 | github.com/spf13/viper v1.19.0 17 | github.com/tidwall/gjson v1.17.1 18 | k8s.io/apimachinery v0.30.2 19 | ) 20 | 21 | require ( 22 | cloud.google.com/go v0.115.0 // indirect 23 | cloud.google.com/go/auth v0.5.1 // indirect 24 | cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect 25 | cloud.google.com/go/compute v1.27.0 // indirect 26 | cloud.google.com/go/compute/metadata v0.3.0 // indirect 27 | cloud.google.com/go/iam v1.1.8 // indirect 28 | cloud.google.com/go/storage v1.42.0 // indirect 29 | github.com/Masterminds/goutils v1.1.1 // indirect 30 | github.com/Masterminds/semver/v3 v3.2.1 // indirect 31 | github.com/Masterminds/sprig/v3 v3.2.3 // indirect 32 | github.com/aws/aws-sdk-go v1.54.6 // indirect 33 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 34 | github.com/felixge/httpsnoop v1.0.4 // indirect 35 | github.com/fsnotify/fsnotify v1.7.0 // indirect 36 | github.com/go-logr/logr v1.4.2 // indirect 37 | github.com/go-logr/stdr v1.2.2 // indirect 38 | github.com/gogo/protobuf v1.3.2 // indirect 39 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 40 | github.com/golang/protobuf v1.5.4 // indirect 41 | github.com/google/gofuzz v1.2.0 // indirect 42 | github.com/google/s2a-go v0.1.7 // indirect 43 | github.com/google/uuid v1.6.0 // indirect 44 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect 45 | github.com/googleapis/gax-go/v2 v2.12.5 // indirect 46 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 47 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 48 | github.com/hashicorp/go-version v1.7.0 // indirect 49 | github.com/hashicorp/hcl v1.0.0 // indirect 50 | github.com/huandu/xstrings v1.5.0 // indirect 51 | github.com/imdario/mergo v0.3.16 // indirect 52 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 53 | github.com/jmespath/go-jmespath v0.4.0 // indirect 54 | github.com/json-iterator/go v1.1.12 // indirect 55 | github.com/klauspost/compress v1.17.9 // indirect 56 | github.com/magiconair/properties v1.8.7 // indirect 57 | github.com/mattn/go-colorable v0.1.13 // indirect 58 | github.com/mattn/go-isatty v0.0.20 // indirect 59 | github.com/mattn/go-runewidth v0.0.15 // indirect 60 | github.com/mitchellh/copystructure v1.2.0 // indirect 61 | github.com/mitchellh/go-homedir v1.1.0 // indirect 62 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 63 | github.com/mitchellh/mapstructure v1.5.0 // indirect 64 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 65 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 66 | github.com/modern-go/reflect2 v1.0.2 // indirect 67 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 68 | github.com/pkg/errors v0.9.1 // indirect 69 | github.com/rivo/uniseg v0.4.7 // indirect 70 | github.com/sagikazarmark/locafero v0.6.0 // indirect 71 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect 72 | github.com/shopspring/decimal v1.4.0 // indirect 73 | github.com/sourcegraph/conc v0.3.0 // indirect 74 | github.com/spf13/afero v1.11.0 // indirect 75 | github.com/spf13/cast v1.6.0 // indirect 76 | github.com/spf13/pflag v1.0.5 // indirect 77 | github.com/stretchr/objx v0.5.2 // indirect 78 | github.com/subosito/gotenv v1.6.0 // indirect 79 | github.com/tidwall/match v1.1.1 // indirect 80 | github.com/tidwall/pretty v1.2.1 // indirect 81 | github.com/ulikunitz/xz v0.5.12 // indirect 82 | go.opencensus.io v0.24.0 // indirect 83 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect 84 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect 85 | go.opentelemetry.io/otel v1.27.0 // indirect 86 | go.opentelemetry.io/otel/metric v1.27.0 // indirect 87 | go.opentelemetry.io/otel/trace v1.27.0 // indirect 88 | go.uber.org/multierr v1.11.0 // indirect 89 | golang.org/x/crypto v0.24.0 // indirect 90 | golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect 91 | golang.org/x/net v0.26.0 // indirect 92 | golang.org/x/oauth2 v0.21.0 // indirect 93 | golang.org/x/sync v0.7.0 // indirect 94 | golang.org/x/sys v0.21.0 // indirect 95 | golang.org/x/text v0.16.0 // indirect 96 | golang.org/x/time v0.5.0 // indirect 97 | google.golang.org/api v0.185.0 // indirect 98 | google.golang.org/appengine v1.6.8 // indirect 99 | google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 // indirect 100 | google.golang.org/genproto/googleapis/api v0.0.0-20240617180043-68d350f18fd4 // indirect 101 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect 102 | google.golang.org/grpc v1.64.0 // indirect 103 | google.golang.org/protobuf v1.34.2 // indirect 104 | gopkg.in/inf.v0 v0.9.1 // indirect 105 | gopkg.in/ini.v1 v1.67.0 // indirect 106 | gopkg.in/yaml.v2 v2.4.0 // indirect 107 | gopkg.in/yaml.v3 v3.0.1 // indirect 108 | k8s.io/klog/v2 v2.130.1 // indirect 109 | k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect 110 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 111 | sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect 112 | sigs.k8s.io/yaml v1.4.0 // indirect 113 | ) 114 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2018 Lee Briggs 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | package main 22 | 23 | import "github.com/apptio/kr8/cmd" 24 | 25 | var version = "snapshot" 26 | 27 | func main() { 28 | cmd.Execute(version) 29 | } 30 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: kr8 2 | theme: 3 | name: 'material' 4 | 5 | nav: 6 | - Home: index.md 7 | - Installation: 8 | - 'OSX': installation/osx.md 9 | - 'Linux': installation/linux.md 10 | - 'Dependencies': installation/dependencies.md 11 | - Concepts: 12 | - 'Overview': concepts/overview.md 13 | - 'Components': concepts/components.md 14 | - 'Clusters': concepts/clusters.md 15 | - 'Helpers': concepts/helpers.md 16 | - Components: 17 | - 'Jsonnet': components/jsonnet.md 18 | - 'YAML': components/yaml.md 19 | - 'Helm': components/helm.md 20 | - 'Jk': components/jk.md 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /scripts/kr8-helpers: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -euo pipefail 4 | 5 | fail() 6 | { 7 | echo "$0: FATAL: $*" 8 | exit 1 9 | } 10 | 11 | check-environment() 12 | { 13 | set +u 14 | if [ -z "$KR8_BASE" ] 15 | then 16 | fail "KR8_BASE environment variable must be set" 17 | fi 18 | if [ -z "$KR8_JSONNET_ARGS" ] 19 | then 20 | KR8_JSONNET_ARGS= 21 | fi 22 | if [ ! -z "$KR8_TRACE" ] 23 | then 24 | set -x 25 | fi 26 | # add shared libsonnet dir to kr8's jsonnet search path 27 | if [ -z "$KR8_JPATH" ] 28 | then 29 | export KR8_JPATH="${KR8_BASE}/lib" 30 | fi 31 | set -u 32 | } 33 | 34 | set-output() 35 | { 36 | # globals 37 | local _base 38 | # allow output and meta dir to be overriden with env vars 39 | set +u 40 | if [ ! -z "$KR8_GENERATED_DIR" ] 41 | then 42 | outputDir="$KR8_GENERATED_DIR/${KR8_COMPONENT}" 43 | else 44 | outputDir="${KR8_BASE}/generated/${KR8_CLUSTER}/${KR8_COMPONENT}" 45 | fi 46 | if [ ! -z "$KR8_METADATA_DIR" ] 47 | then 48 | metaDir="$KR8_METADATA_DIR/${KR8_COMPONENT}" 49 | else 50 | metaDir="${KR8_BASE}/metadata//${KR8_CLUSTER}/${KR8_COMPONENT}" 51 | fi 52 | set -u 53 | } 54 | 55 | clean-output() 56 | { 57 | set-output 58 | # Clean output directory, since we will replace its contents 59 | rm -fr $outputDir $metaDir 60 | mkdir -p $outputDir $metaDir 61 | } 62 | 63 | _helm-render() { 64 | local _chart="$1" 65 | local _outfile="$2" 66 | 67 | # render helm values for the chart 68 | kr8 jsonnet render --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format yaml $KR8_JSONNET_ARGS "${_chart}-values.jsonnet" > "$metaDir/${_chart}-values.jsonnet" 69 | # render chart 70 | local releasename=$(kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.release_name" --notunset) 71 | local namespace=$(kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.namespace" --notunset) 72 | 73 | # record metadata 74 | set-meta 75 | 76 | if [[ $(helm version --client --short) =~ ^v3 ]] 77 | then 78 | local userelname="$releasename" 79 | else 80 | local userelname="--name $releasename" 81 | fi 82 | helm template $userelname --namespace "$namespace" --values "$metaDir/${_chart}-values.jsonnet" "./charts/${_chart}" | kr8 yaml helmclean > "$_outfile" 83 | } 84 | 85 | helm-render() { 86 | local _chart="$1" 87 | local tmpfile 88 | 89 | check-environment 90 | set-output 91 | 92 | tmpfile=$(mktemp) 93 | _helm-render "$_chart" "$tmpfile" 94 | kr8 jsonnet render --prune=false --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream $KR8_JSONNET_ARGS $KR8_BASE/lib/postprocess.jsonnet --ext-str-file inputYaml="$tmpfile" > "$outputDir/${_chart}.yaml" 95 | rm -f "$tmpfile" 96 | } 97 | 98 | set-meta(){ 99 | check-environment 100 | set-output 101 | 102 | local namespace 103 | local releasename 104 | namespace=$(set -eu; kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.namespace" --notunset) 105 | releasename=$(kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.release_name" --notunset) 106 | kubecfg_gc_enable=$(kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.kubecfg_gc_enable") 107 | 108 | echo "$namespace" > "$metaDir/namespace_default" 109 | echo "${KR8_COMPONENT}_${namespace}_${releasename}" > "$metaDir/gc_tag" 110 | 111 | # this file indicates that gc should be used 112 | if [ ! -z "$kubecfg_gc_enable" -a "$kubecfg_gc_enable" != "false" ] 113 | then 114 | echo "$kubecfg_gc_enable" > "$metaDir/gc_enable" 115 | else 116 | rm -f "$metaDir/gc_enable" 117 | fi 118 | 119 | kubecfg_update_args=$(kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}.kubecfg_update_args") 120 | if [ ! -z "$kubecfg_update_args" ] 121 | then 122 | echo "$kubecfg_update_args" > "$metaDir/kubecfg_update_args" 123 | fi 124 | } 125 | 126 | 127 | # Render a helm chart, and post-process with a jsonnet patch 128 | helm-render-with-patch() { 129 | local _chart="$1" 130 | local _patch="$2" 131 | local tmpfile 132 | local tmpfile2 133 | 134 | check-environment 135 | set-output 136 | 137 | tmpfile=$(mktemp) 138 | tmpfile2=$(mktemp) 139 | _helm-render "$_chart" "$tmpfile" 140 | kr8 jsonnet render --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream $KR8_JSONNET_ARGS patches.jsonnet --ext-str-file inputYaml="$tmpfile" > "$tmpfile2" 141 | rm -f $tmpfile 142 | kr8 jsonnet render --prune=false --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream $KR8_JSONNET_ARGS $KR8_BASE/lib/postprocess.jsonnet --ext-str-file inputYaml="$tmpfile2" > "$outputDir/${_chart}.yaml" 143 | rm -f $tmpfile2 144 | } 145 | 146 | yaml-install() { 147 | check-environment 148 | set-output 149 | set-meta 150 | 151 | # copy each yaml file to the output directory, passing htem through helmclean, which validates that they are k8s resources 152 | for yaml in "$@" 153 | do 154 | local outf 155 | outf=$(basename $yaml) 156 | kr8 jsonnet render --prune=false --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream $KR8_JSONNET_ARGS $KR8_BASE/lib/postprocess.jsonnet --ext-str-file inputYaml="$yaml" > "$outputDir/$outf" 157 | # kr8 yaml helmclean < "$yaml" > "$outputDir/$outf" 158 | done 159 | } 160 | 161 | jsonnet-render() { 162 | check-environment 163 | set-output 164 | set-meta 165 | local tmpfile 166 | 167 | # Process each jsonnet file, and output yaml stream to output directory 168 | # The jsonnet files must output a list of objects 169 | tmpfile=$(mktemp) 170 | for jsonnet in "$@" 171 | do 172 | local outf 173 | outf=$(basename $jsonnet | sed 's/\.jsonnet$/.yaml/') 174 | kr8 jsonnet render --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream "$jsonnet" "$@" $KR8_JSONNET_ARGS > "$tmpfile" 175 | kr8 jsonnet render --prune=false --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --format stream $KR8_JSONNET_ARGS $KR8_BASE/lib/postprocess.jsonnet --ext-str-file inputYaml="$tmpfile" > "$outputDir/$outf" 176 | done 177 | rm -f "$tmpfile" 178 | } 179 | 180 | jk-render() { 181 | check-environment 182 | set-output 183 | set-meta 184 | local _js="$1" 185 | local tmpfile 186 | 187 | tmpfile=$(mktemp) 188 | # Render the params file into a temporary JSON file 189 | kr8 cluster params --cluster "$KR8_CLUSTER" --component "$KR8_COMPONENT" --param "${KR8_COMPONENT}" > "$tmpfile" 190 | jk run "$_js" -f "$tmpfile" -o "$outputDir" 191 | 192 | 193 | } 194 | 195 | [ -z "$*" ] && fail "No sub-command provided" 196 | case "$1" in 197 | helm-render-with-patch) 198 | shift; helm-render-with-patch "$@" 199 | ;; 200 | helm-render) 201 | shift; helm-render "$@" 202 | ;; 203 | yaml-install) 204 | shift; yaml-install "$@" 205 | ;; 206 | jsonnet-render) 207 | shift; jsonnet-render "$@" 208 | ;; 209 | clean-output) 210 | shift; clean-output 211 | ;; 212 | check-environment) 213 | shift; check-environment 214 | ;; 215 | jk-render) 216 | shift; jk-render "$@" 217 | ;; 218 | *) 219 | fail "Unknown sub-command: $1" 220 | esac 221 | -------------------------------------------------------------------------------- /site/assets/fonts/material-icons.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 3 | * use this file except in compliance with the License. You may obtain a copy 4 | * of the License at: 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE 9 | * DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | * SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND 12 | * LIMITATIONS UNDER THE LICENSE. 13 | */@font-face{font-family:"Material Icons";font-style:normal;font-weight:400;src:local("Material Icons"),local("MaterialIcons-Regular"),url("specimen/MaterialIcons-Regular.woff2") format("woff2"),url("specimen/MaterialIcons-Regular.woff") format("woff"),url("specimen/MaterialIcons-Regular.ttf") format("truetype")} -------------------------------------------------------------------------------- /site/assets/fonts/specimen/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/FontAwesome.ttf -------------------------------------------------------------------------------- /site/assets/fonts/specimen/FontAwesome.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/FontAwesome.woff -------------------------------------------------------------------------------- /site/assets/fonts/specimen/FontAwesome.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/FontAwesome.woff2 -------------------------------------------------------------------------------- /site/assets/fonts/specimen/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /site/assets/fonts/specimen/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /site/assets/fonts/specimen/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/fonts/specimen/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /site/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/assets/images/favicon.png -------------------------------------------------------------------------------- /site/assets/images/icons/bitbucket.1b09e088.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/assets/images/icons/github.f0b8504a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/assets/images/icons/gitlab.6dd19c00.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.da.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,m,i;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,m=e.stemmerSupport.SnowballProgram,i=new function(){var i,t,n,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new m;function l(){var e,r=c.limit-c.cursor;c.cursor>=t&&(e=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var e,r=c.cursor;return function(){var e,r=c.cursor+3;if(t=c.limit,0<=r&&r<=c.limit){for(i=r;;){if(e=c.cursor,c.in_grouping(d,97,248)){c.cursor=e;break}if((c.cursor=e)>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(t=c.cursor)=t&&(r=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,n=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-n,c.cursor>=t&&(r=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=t&&(e=c.limit_backward,c.limit_backward=t,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,n=c.slice_to(n),c.limit_backward=e,c.eq_v_b(n)&&c.slice_del()):c.limit_backward=e),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.de.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var _,p,r;e.de=function(){this.pipeline.reset(),this.pipeline.add(e.de.trimmer,e.de.stopWordFilter,e.de.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.de.stemmer))},e.de.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.de.trimmer=e.trimmerSupport.generateTrimmer(e.de.wordCharacters),e.Pipeline.registerFunction(e.de.trimmer,"trimmer-de"),e.de.stemmer=(_=e.stemmerSupport.Among,p=e.stemmerSupport.SnowballProgram,r=new function(){var r,n,i,s=[new _("",-1,6),new _("U",0,2),new _("Y",0,1),new _("ä",0,3),new _("ö",0,4),new _("ü",0,5)],o=[new _("e",-1,2),new _("em",-1,1),new _("en",-1,2),new _("ern",-1,1),new _("er",-1,1),new _("s",-1,3),new _("es",5,2)],c=[new _("en",-1,1),new _("er",-1,1),new _("st",-1,2),new _("est",2,1)],u=[new _("ig",-1,1),new _("lich",-1,1)],a=[new _("end",-1,1),new _("ig",-1,2),new _("ung",-1,1),new _("lich",-1,3),new _("isch",-1,2),new _("ik",-1,2),new _("heit",-1,3),new _("keit",-1,4)],t=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32,8],d=[117,30,5],l=[117,30,4],m=new p;function h(e,r,n){return!(!m.eq_s(1,e)||(m.ket=m.cursor,!m.in_grouping(t,97,252)))&&(m.slice_from(r),m.cursor=n,!0)}function w(){for(;!m.in_grouping(t,97,252);){if(m.cursor>=m.limit)return!0;m.cursor++}for(;!m.out_grouping(t,97,252);){if(m.cursor>=m.limit)return!0;m.cursor++}return!1}function f(){return i<=m.cursor}function b(){return n<=m.cursor}this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var e=m.cursor;return function(){for(var e,r,n,i,s=m.cursor;;)if(e=m.cursor,m.bra=e,m.eq_s(1,"ß"))m.ket=m.cursor,m.slice_from("ss");else{if(e>=m.limit)break;m.cursor=e+1}for(m.cursor=s;;)for(r=m.cursor;;){if(n=m.cursor,m.in_grouping(t,97,252)){if(i=m.cursor,m.bra=i,h("u","U",n))break;if(m.cursor=i,h("y","Y",n))break}if(n>=m.limit)return m.cursor=r;m.cursor=n+1}}(),m.cursor=e,function(){i=m.limit,n=i;var e=m.cursor+3;0<=e&&e<=m.limit&&(r=e,w()||((i=m.cursor)=m.limit)return;m.cursor++}}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.de.stemmer,"stemmer-de"),e.de.stopWordFilter=e.generateStopWordFilter("aber alle allem allen aller alles als also am an ander andere anderem anderen anderer anderes anderm andern anderr anders auch auf aus bei bin bis bist da damit dann das dasselbe dazu daß dein deine deinem deinen deiner deines dem demselben den denn denselben der derer derselbe derselben des desselben dessen dich die dies diese dieselbe dieselben diesem diesen dieser dieses dir doch dort du durch ein eine einem einen einer eines einig einige einigem einigen einiger einiges einmal er es etwas euch euer eure eurem euren eurer eures für gegen gewesen hab habe haben hat hatte hatten hier hin hinter ich ihm ihn ihnen ihr ihre ihrem ihren ihrer ihres im in indem ins ist jede jedem jeden jeder jedes jene jenem jenen jener jenes jetzt kann kein keine keinem keinen keiner keines können könnte machen man manche manchem manchen mancher manches mein meine meinem meinen meiner meines mich mir mit muss musste nach nicht nichts noch nun nur ob oder ohne sehr sein seine seinem seinen seiner seines selbst sich sie sind so solche solchem solchen solcher solches soll sollte sondern sonst um und uns unse unsem unsen unser unses unter viel vom von vor war waren warst was weg weil weiter welche welchem welchen welcher welches wenn werde werden wie wieder will wir wird wirst wo wollen wollte während würde würden zu zum zur zwar zwischen über".split(" ")),e.Pipeline.registerFunction(e.de.stopWordFilter,"stopWordFilter-de")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.du.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var v,q,r;console.warn('[Lunr Languages] Please use the "nl" instead of the "du". The "nl" code is the standard code for Dutch language, and "du" will be removed in the next major versions.'),e.du=function(){this.pipeline.reset(),this.pipeline.add(e.du.trimmer,e.du.stopWordFilter,e.du.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.du.stemmer))},e.du.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.du.trimmer=e.trimmerSupport.generateTrimmer(e.du.wordCharacters),e.Pipeline.registerFunction(e.du.trimmer,"trimmer-du"),e.du.stemmer=(v=e.stemmerSupport.Among,q=e.stemmerSupport.SnowballProgram,r=new function(){var r,i,u,o=[new v("",-1,6),new v("á",0,1),new v("ä",0,1),new v("é",0,2),new v("ë",0,2),new v("í",0,3),new v("ï",0,3),new v("ó",0,4),new v("ö",0,4),new v("ú",0,5),new v("ü",0,5)],n=[new v("",-1,3),new v("I",0,2),new v("Y",0,1)],t=[new v("dd",-1,-1),new v("kk",-1,-1),new v("tt",-1,-1)],c=[new v("ene",-1,2),new v("se",-1,3),new v("en",-1,2),new v("heden",2,1),new v("s",-1,3)],a=[new v("end",-1,1),new v("ig",-1,2),new v("ing",-1,1),new v("lijk",-1,3),new v("baar",-1,4),new v("bar",-1,5)],l=[new v("aa",-1,-1),new v("ee",-1,-1),new v("oo",-1,-1),new v("uu",-1,-1)],m=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],d=[1,0,0,17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],f=[17,67,16,1,0,0,0,0,0,0,0,0,0,0,0,0,128],_=new q;function s(e){return(_.cursor=e)>=_.limit||(_.cursor++,!1)}function w(){for(;!_.in_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}for(;!_.out_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}function b(){return i<=_.cursor}function p(){return r<=_.cursor}function g(){var e=_.limit-_.cursor;_.find_among_b(t,3)&&(_.cursor=_.limit-e,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del()))}function h(){var e;u=!1,_.ket=_.cursor,_.eq_s_b(1,"e")&&(_.bra=_.cursor,b()&&(e=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-e,_.slice_del(),u=!0,g())))}function k(){var e;b()&&(e=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-e,_.eq_s_b(3,"gem")||(_.cursor=_.limit-e,_.slice_del(),g())))}this.setCurrent=function(e){_.setCurrent(e)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var e=_.cursor;return function(){for(var e,r,i,n=_.cursor;;){if(_.bra=_.cursor,e=_.find_among(o,11))switch(_.ket=_.cursor,e){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}for(_.cursor=n,_.bra=n,_.eq_s(1,"y")?(_.ket=_.cursor,_.slice_from("Y")):_.cursor=n;;)if(r=_.cursor,_.in_grouping(m,97,232)){if(i=_.cursor,_.bra=i,_.eq_s(1,"i"))_.ket=_.cursor,_.in_grouping(m,97,232)&&(_.slice_from("I"),_.cursor=r);else if(_.cursor=i,_.eq_s(1,"y"))_.ket=_.cursor,_.slice_from("Y"),_.cursor=r;else if(s(r))break}else if(s(r))break}(),_.cursor=e,i=_.limit,r=i,w()||((i=_.cursor)<3&&(i=3),w()||(r=_.cursor)),_.limit_backward=e,_.cursor=_.limit,function(){var e,r,i,n,o,t,s=_.limit-_.cursor;if(_.ket=_.cursor,e=_.find_among_b(c,5))switch(_.bra=_.cursor,e){case 1:b()&&_.slice_from("heid");break;case 2:k();break;case 3:b()&&_.out_grouping_b(f,97,232)&&_.slice_del()}if(_.cursor=_.limit-s,h(),_.cursor=_.limit-s,_.ket=_.cursor,_.eq_s_b(4,"heid")&&(_.bra=_.cursor,p()&&(r=_.limit-_.cursor,_.eq_s_b(1,"c")||(_.cursor=_.limit-r,_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,"en")&&(_.bra=_.cursor,k())))),_.cursor=_.limit-s,_.ket=_.cursor,e=_.find_among_b(a,6))switch(_.bra=_.cursor,e){case 1:if(p()){if(_.slice_del(),i=_.limit-_.cursor,_.ket=_.cursor,_.eq_s_b(2,"ig")&&(_.bra=_.cursor,p()&&(n=_.limit-_.cursor,!_.eq_s_b(1,"e")))){_.cursor=_.limit-n,_.slice_del();break}_.cursor=_.limit-i,g()}break;case 2:p()&&(o=_.limit-_.cursor,_.eq_s_b(1,"e")||(_.cursor=_.limit-o,_.slice_del()));break;case 3:p()&&(_.slice_del(),h());break;case 4:p()&&_.slice_del();break;case 5:p()&&u&&_.slice_del()}_.cursor=_.limit-s,_.out_grouping_b(d,73,232)&&(t=_.limit-_.cursor,_.find_among_b(l,4)&&_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-t,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del())))}(),_.cursor=_.limit_backward,function(){for(var e;;)if(_.bra=_.cursor,e=_.find_among(n,3))switch(_.ket=_.cursor,e){case 1:_.slice_from("y");break;case 2:_.slice_from("i");break;case 3:if(_.cursor>=_.limit)return;_.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.du.stemmer,"stemmer-du"),e.du.stopWordFilter=e.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),e.Pipeline.registerFunction(e.du.stopWordFilter,"stopWordFilter-du")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.fi.js: -------------------------------------------------------------------------------- 1 | !function(i,e){"function"==typeof define&&define.amd?define(e):"object"==typeof exports?module.exports=e():e()(i.lunr)}(this,function(){return function(i){if(void 0===i)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===i.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var v,C,e;i.fi=function(){this.pipeline.reset(),this.pipeline.add(i.fi.trimmer,i.fi.stopWordFilter,i.fi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(i.fi.stemmer))},i.fi.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",i.fi.trimmer=i.trimmerSupport.generateTrimmer(i.fi.wordCharacters),i.Pipeline.registerFunction(i.fi.trimmer,"trimmer-fi"),i.fi.stemmer=(v=i.stemmerSupport.Among,C=i.stemmerSupport.SnowballProgram,e=new function(){var n,t,l,o,r=[new v("pa",-1,1),new v("sti",-1,2),new v("kaan",-1,1),new v("han",-1,1),new v("kin",-1,1),new v("hän",-1,1),new v("kään",-1,1),new v("ko",-1,1),new v("pä",-1,1),new v("kö",-1,1)],s=[new v("lla",-1,-1),new v("na",-1,-1),new v("ssa",-1,-1),new v("ta",-1,-1),new v("lta",3,-1),new v("sta",3,-1)],a=[new v("llä",-1,-1),new v("nä",-1,-1),new v("ssä",-1,-1),new v("tä",-1,-1),new v("ltä",3,-1),new v("stä",3,-1)],u=[new v("lle",-1,-1),new v("ine",-1,-1)],c=[new v("nsa",-1,3),new v("mme",-1,3),new v("nne",-1,3),new v("ni",-1,2),new v("si",-1,1),new v("an",-1,4),new v("en",-1,6),new v("än",-1,5),new v("nsä",-1,3)],i=[new v("aa",-1,-1),new v("ee",-1,-1),new v("ii",-1,-1),new v("oo",-1,-1),new v("uu",-1,-1),new v("ää",-1,-1),new v("öö",-1,-1)],m=[new v("a",-1,8),new v("lla",0,-1),new v("na",0,-1),new v("ssa",0,-1),new v("ta",0,-1),new v("lta",4,-1),new v("sta",4,-1),new v("tta",4,9),new v("lle",-1,-1),new v("ine",-1,-1),new v("ksi",-1,-1),new v("n",-1,7),new v("han",11,1),new v("den",11,-1,q),new v("seen",11,-1,j),new v("hen",11,2),new v("tten",11,-1,q),new v("hin",11,3),new v("siin",11,-1,q),new v("hon",11,4),new v("hän",11,5),new v("hön",11,6),new v("ä",-1,8),new v("llä",22,-1),new v("nä",22,-1),new v("ssä",22,-1),new v("tä",22,-1),new v("ltä",26,-1),new v("stä",26,-1),new v("ttä",26,9)],w=[new v("eja",-1,-1),new v("mma",-1,1),new v("imma",1,-1),new v("mpa",-1,1),new v("impa",3,-1),new v("mmi",-1,1),new v("immi",5,-1),new v("mpi",-1,1),new v("impi",7,-1),new v("ejä",-1,-1),new v("mmä",-1,1),new v("immä",10,-1),new v("mpä",-1,1),new v("impä",12,-1)],_=[new v("i",-1,-1),new v("j",-1,-1)],k=[new v("mma",-1,1),new v("imma",0,-1)],b=[17,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],e=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],f=[17,97,24,1,0,0,0,0,0,0,0,0,0,0,0,0,8,0,32],h=new C;function p(){for(var i;i=h.cursor,!h.in_grouping(d,97,246);){if((h.cursor=i)>=h.limit)return!0;h.cursor++}for(h.cursor=i;!h.out_grouping(d,97,246);){if(h.cursor>=h.limit)return!0;h.cursor++}return!1}function g(){var i,e;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(r,10)){switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:if(!h.in_grouping_b(f,97,246))return;break;case 2:if(!(l<=h.cursor))return}h.slice_del()}else h.limit_backward=e}function j(){return h.find_among_b(i,7)}function q(){return h.eq_s_b(1,"i")&&h.in_grouping_b(e,97,246)}this.setCurrent=function(i){h.setCurrent(i)},this.getCurrent=function(){return h.getCurrent()},this.stem=function(){var i,e=h.cursor;return o=h.limit,l=o,p()||(o=h.cursor,p()||(l=h.cursor)),n=!1,h.limit_backward=e,h.cursor=h.limit,g(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(c,9))switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:r=h.limit-h.cursor,h.eq_s_b(1,"k")||(h.cursor=h.limit-r,h.slice_del());break;case 2:h.slice_del(),h.ket=h.cursor,h.eq_s_b(3,"kse")&&(h.bra=h.cursor,h.slice_from("ksi"));break;case 3:h.slice_del();break;case 4:h.find_among_b(s,6)&&h.slice_del();break;case 5:h.find_among_b(a,6)&&h.slice_del();break;case 6:h.find_among_b(u,2)&&h.slice_del()}else h.limit_backward=e}(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=o)if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,i=h.find_among_b(m,30)){switch(h.bra=h.cursor,h.limit_backward=e,i){case 1:if(!h.eq_s_b(1,"a"))return;break;case 2:case 9:if(!h.eq_s_b(1,"e"))return;break;case 3:if(!h.eq_s_b(1,"i"))return;break;case 4:if(!h.eq_s_b(1,"o"))return;break;case 5:if(!h.eq_s_b(1,"ä"))return;break;case 6:if(!h.eq_s_b(1,"ö"))return;break;case 7:if(r=h.limit-h.cursor,!j()&&(h.cursor=h.limit-r,!h.eq_s_b(2,"ie"))){h.cursor=h.limit-r;break}if(h.cursor=h.limit-r,h.cursor<=h.limit_backward){h.cursor=h.limit-r;break}h.cursor--,h.bra=h.cursor;break;case 8:if(!h.in_grouping_b(d,97,246)||!h.out_grouping_b(d,97,246))return}h.slice_del(),n=!0}else h.limit_backward=e}(),h.cursor=h.limit,function(){var i,e,r;if(h.cursor>=l)if(e=h.limit_backward,h.limit_backward=l,h.ket=h.cursor,i=h.find_among_b(w,14)){if(h.bra=h.cursor,h.limit_backward=e,1==i){if(r=h.limit-h.cursor,h.eq_s_b(2,"po"))return;h.cursor=h.limit-r}h.slice_del()}else h.limit_backward=e}(),h.cursor=h.limit,h.cursor=(n?h.cursor>=o&&(i=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,h.find_among_b(_,2)?(h.bra=h.cursor,h.limit_backward=i,h.slice_del()):h.limit_backward=i):(h.cursor=h.limit,function(){var i,e,r,n,t,s;if(h.cursor>=o){if(e=h.limit_backward,h.limit_backward=o,h.ket=h.cursor,h.eq_s_b(1,"t")&&(h.bra=h.cursor,r=h.limit-h.cursor,h.in_grouping_b(d,97,246)&&(h.cursor=h.limit-r,h.slice_del(),h.limit_backward=e,n=h.limit-h.cursor,h.cursor>=l&&(h.cursor=l,t=h.limit_backward,h.limit_backward=h.cursor,h.cursor=h.limit-n,h.ket=h.cursor,i=h.find_among_b(k,2))))){if(h.bra=h.cursor,h.limit_backward=t,1==i){if(s=h.limit-h.cursor,h.eq_s_b(2,"po"))return;h.cursor=h.limit-s}return h.slice_del()}h.limit_backward=e}}()),h.limit),function(){var i,e,r,n;if(h.cursor>=o){for(i=h.limit_backward,h.limit_backward=o,e=h.limit-h.cursor,j()&&(h.cursor=h.limit-e,h.ket=h.cursor,h.cursor>h.limit_backward&&(h.cursor--,h.bra=h.cursor,h.slice_del())),h.cursor=h.limit-e,h.ket=h.cursor,h.in_grouping_b(b,97,228)&&(h.bra=h.cursor,h.out_grouping_b(d,97,246)&&h.slice_del()),h.cursor=h.limit-e,h.ket=h.cursor,h.eq_s_b(1,"j")&&(h.bra=h.cursor,r=h.limit-h.cursor,h.eq_s_b(1,"o")?h.slice_del():(h.cursor=h.limit-r,h.eq_s_b(1,"u")&&h.slice_del())),h.cursor=h.limit-e,h.ket=h.cursor,h.eq_s_b(1,"o")&&(h.bra=h.cursor,h.eq_s_b(1,"j")&&h.slice_del()),h.cursor=h.limit-e,h.limit_backward=i;;){if(n=h.limit-h.cursor,h.out_grouping_b(d,97,246)){h.cursor=h.limit-n;break}if(h.cursor=h.limit-n,h.cursor<=h.limit_backward)return;h.cursor--}h.ket=h.cursor,h.cursor>h.limit_backward&&(h.cursor--,h.bra=h.cursor,t=h.slice_to(),h.eq_v_b(t)&&h.slice_del())}}(),!0}},function(i){return"function"==typeof i.update?i.update(function(i){return e.setCurrent(i),e.stem(),e.getCurrent()}):(e.setCurrent(i),e.stem(),e.getCurrent())}),i.Pipeline.registerFunction(i.fi.stemmer,"stemmer-fi"),i.fi.stopWordFilter=i.generateStopWordFilter("ei eivät emme en et ette että he heidän heidät heihin heille heillä heiltä heissä heistä heitä hän häneen hänelle hänellä häneltä hänen hänessä hänestä hänet häntä itse ja johon joiden joihin joiksi joilla joille joilta joina joissa joista joita joka joksi jolla jolle jolta jona jonka jos jossa josta jota jotka kanssa keiden keihin keiksi keille keillä keiltä keinä keissä keistä keitä keneen keneksi kenelle kenellä keneltä kenen kenenä kenessä kenestä kenet ketkä ketkä ketä koska kuin kuka kun me meidän meidät meihin meille meillä meiltä meissä meistä meitä mihin miksi mikä mille millä miltä minkä minkä minua minulla minulle minulta minun minussa minusta minut minuun minä minä missä mistä mitkä mitä mukaan mutta ne niiden niihin niiksi niille niillä niiltä niin niin niinä niissä niistä niitä noiden noihin noiksi noilla noille noilta noin noina noissa noista noita nuo nyt näiden näihin näiksi näille näillä näiltä näinä näissä näistä näitä nämä ole olemme olen olet olette oli olimme olin olisi olisimme olisin olisit olisitte olisivat olit olitte olivat olla olleet ollut on ovat poikki se sekä sen siihen siinä siitä siksi sille sillä sillä siltä sinua sinulla sinulle sinulta sinun sinussa sinusta sinut sinuun sinä sinä sitä tai te teidän teidät teihin teille teillä teiltä teissä teistä teitä tuo tuohon tuoksi tuolla tuolle tuolta tuon tuona tuossa tuosta tuota tähän täksi tälle tällä tältä tämä tämän tänä tässä tästä tätä vaan vai vaikka yli".split(" ")),i.Pipeline.registerFunction(i.fi.stopWordFilter,"stopWordFilter-fi")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.fr.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,y,s;e.fr=function(){this.pipeline.reset(),this.pipeline.add(e.fr.trimmer,e.fr.stopWordFilter,e.fr.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.fr.stemmer))},e.fr.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.fr.trimmer=e.trimmerSupport.generateTrimmer(e.fr.wordCharacters),e.Pipeline.registerFunction(e.fr.trimmer,"trimmer-fr"),e.fr.stemmer=(r=e.stemmerSupport.Among,y=e.stemmerSupport.SnowballProgram,s=new function(){var s,i,t,n=[new r("col",-1,-1),new r("par",-1,-1),new r("tap",-1,-1)],u=[new r("",-1,4),new r("I",0,1),new r("U",0,2),new r("Y",0,3)],o=[new r("iqU",-1,3),new r("abl",-1,3),new r("Ièr",-1,4),new r("ièr",-1,4),new r("eus",-1,2),new r("iv",-1,1)],c=[new r("ic",-1,2),new r("abil",-1,1),new r("iv",-1,3)],a=[new r("iqUe",-1,1),new r("atrice",-1,2),new r("ance",-1,1),new r("ence",-1,5),new r("logie",-1,3),new r("able",-1,1),new r("isme",-1,1),new r("euse",-1,11),new r("iste",-1,1),new r("ive",-1,8),new r("if",-1,8),new r("usion",-1,4),new r("ation",-1,2),new r("ution",-1,4),new r("ateur",-1,2),new r("iqUes",-1,1),new r("atrices",-1,2),new r("ances",-1,1),new r("ences",-1,5),new r("logies",-1,3),new r("ables",-1,1),new r("ismes",-1,1),new r("euses",-1,11),new r("istes",-1,1),new r("ives",-1,8),new r("ifs",-1,8),new r("usions",-1,4),new r("ations",-1,2),new r("utions",-1,4),new r("ateurs",-1,2),new r("ments",-1,15),new r("ements",30,6),new r("issements",31,12),new r("ités",-1,7),new r("ment",-1,15),new r("ement",34,6),new r("issement",35,12),new r("amment",34,13),new r("emment",34,14),new r("aux",-1,10),new r("eaux",39,9),new r("eux",-1,1),new r("ité",-1,7)],l=[new r("ira",-1,1),new r("ie",-1,1),new r("isse",-1,1),new r("issante",-1,1),new r("i",-1,1),new r("irai",4,1),new r("ir",-1,1),new r("iras",-1,1),new r("ies",-1,1),new r("îmes",-1,1),new r("isses",-1,1),new r("issantes",-1,1),new r("îtes",-1,1),new r("is",-1,1),new r("irais",13,1),new r("issais",13,1),new r("irions",-1,1),new r("issions",-1,1),new r("irons",-1,1),new r("issons",-1,1),new r("issants",-1,1),new r("it",-1,1),new r("irait",21,1),new r("issait",21,1),new r("issant",-1,1),new r("iraIent",-1,1),new r("issaIent",-1,1),new r("irent",-1,1),new r("issent",-1,1),new r("iront",-1,1),new r("ît",-1,1),new r("iriez",-1,1),new r("issiez",-1,1),new r("irez",-1,1),new r("issez",-1,1)],w=[new r("a",-1,3),new r("era",0,2),new r("asse",-1,3),new r("ante",-1,3),new r("ée",-1,2),new r("ai",-1,3),new r("erai",5,2),new r("er",-1,2),new r("as",-1,3),new r("eras",8,2),new r("âmes",-1,3),new r("asses",-1,3),new r("antes",-1,3),new r("âtes",-1,3),new r("ées",-1,2),new r("ais",-1,3),new r("erais",15,2),new r("ions",-1,1),new r("erions",17,2),new r("assions",17,3),new r("erons",-1,2),new r("ants",-1,3),new r("és",-1,2),new r("ait",-1,3),new r("erait",23,2),new r("ant",-1,3),new r("aIent",-1,3),new r("eraIent",26,2),new r("èrent",-1,2),new r("assent",-1,3),new r("eront",-1,2),new r("ât",-1,3),new r("ez",-1,2),new r("iez",32,2),new r("eriez",33,2),new r("assiez",33,3),new r("erez",32,2),new r("é",-1,2)],f=[new r("e",-1,3),new r("Ière",0,2),new r("ière",0,2),new r("ion",-1,1),new r("Ier",-1,2),new r("ier",-1,2),new r("ë",-1,4)],m=[new r("ell",-1,-1),new r("eill",-1,-1),new r("enn",-1,-1),new r("onn",-1,-1),new r("ett",-1,-1)],_=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,128,130,103,8,5],b=[1,65,20,0,0,0,0,0,0,0,0,0,0,0,0,0,128],d=new y;function k(e,r,s){return!(!d.eq_s(1,e)||(d.ket=d.cursor,!d.in_grouping(_,97,251)))&&(d.slice_from(r),d.cursor=s,!0)}function p(e,r,s){return!!d.eq_s(1,e)&&(d.ket=d.cursor,d.slice_from(r),d.cursor=s,!0)}function g(){for(;!d.in_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}for(;!d.out_grouping(_,97,251);){if(d.cursor>=d.limit)return!0;d.cursor++}return!1}function q(){return t<=d.cursor}function v(){return i<=d.cursor}function h(){return s<=d.cursor}function z(){if(!function(){var e,r;if(d.ket=d.cursor,e=d.find_among_b(a,43)){switch(d.bra=d.cursor,e){case 1:if(!h())return!1;d.slice_del();break;case 2:if(!h())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")&&(d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU"));break;case 3:if(!h())return!1;d.slice_from("log");break;case 4:if(!h())return!1;d.slice_from("u");break;case 5:if(!h())return!1;d.slice_from("ent");break;case 6:if(!q())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(o,6))switch(d.bra=d.cursor,e){case 1:h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&d.slice_del()));break;case 2:h()?d.slice_del():v()&&d.slice_from("eux");break;case 3:h()&&d.slice_del();break;case 4:q()&&d.slice_from("i")}break;case 7:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,e=d.find_among_b(c,3))switch(d.bra=d.cursor,e){case 1:h()?d.slice_del():d.slice_from("abl");break;case 2:h()?d.slice_del():d.slice_from("iqU");break;case 3:h()&&d.slice_del()}break;case 8:if(!h())return!1;if(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,h()&&(d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"ic")))){d.bra=d.cursor,h()?d.slice_del():d.slice_from("iqU");break}break;case 9:d.slice_from("eau");break;case 10:if(!v())return!1;d.slice_from("al");break;case 11:if(h())d.slice_del();else{if(!v())return!1;d.slice_from("eux")}break;case 12:if(!v()||!d.out_grouping_b(_,97,251))return!1;d.slice_del();break;case 13:return q()&&d.slice_from("ant"),!1;case 14:return q()&&d.slice_from("ent"),!1;case 15:return r=d.limit-d.cursor,d.in_grouping_b(_,97,251)&&q()&&(d.cursor=d.limit-r,d.slice_del()),!1}return!0}return!1}()&&(d.cursor=d.limit,!function(){var e,r;if(d.cursor=t){if(s=d.limit_backward,d.limit_backward=t,d.ket=d.cursor,e=d.find_among_b(f,7))switch(d.bra=d.cursor,e){case 1:if(h()){if(i=d.limit-d.cursor,!d.eq_s_b(1,"s")&&(d.cursor=d.limit-i,!d.eq_s_b(1,"t")))break;d.slice_del()}break;case 2:d.slice_from("i");break;case 3:d.slice_del();break;case 4:d.eq_s_b(2,"gu")&&d.slice_del()}d.limit_backward=s}}();d.cursor=d.limit,d.ket=d.cursor,d.eq_s_b(1,"Y")?(d.bra=d.cursor,d.slice_from("i")):(d.cursor=d.limit,d.eq_s_b(1,"ç")&&(d.bra=d.cursor,d.slice_from("c")))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var e,r=d.cursor;return function(){for(var e,r;;){if(e=d.cursor,d.in_grouping(_,97,251)){if(d.bra=d.cursor,r=d.cursor,k("u","U",e))continue;if(d.cursor=r,k("i","I",e))continue;if(d.cursor=r,p("y","Y",e))continue}if(d.cursor=e,!k("y","Y",d.bra=e)){if(d.cursor=e,d.eq_s(1,"q")&&(d.bra=d.cursor,p("u","U",e)))continue;if((d.cursor=e)>=d.limit)return;d.cursor++}}}(),d.cursor=r,function(){var e=d.cursor;if(t=d.limit,s=i=t,d.in_grouping(_,97,251)&&d.in_grouping(_,97,251)&&d.cursor=d.limit){d.cursor=t;break}d.cursor++}while(!d.in_grouping(_,97,251))}t=d.cursor,d.cursor=e,g()||(i=d.cursor,g()||(s=d.cursor))}(),d.limit_backward=r,d.cursor=d.limit,z(),d.cursor=d.limit,e=d.limit-d.cursor,d.find_among_b(m,5)&&(d.cursor=d.limit-e,d.ket=d.cursor,d.cursor>d.limit_backward&&(d.cursor--,d.bra=d.cursor,d.slice_del())),d.cursor=d.limit,function(){for(var e,r=1;d.out_grouping_b(_,97,251);)r--;if(r<=0){if(d.ket=d.cursor,e=d.limit-d.cursor,!d.eq_s_b(1,"é")&&(d.cursor=d.limit-e,!d.eq_s_b(1,"è")))return;d.bra=d.cursor,d.slice_from("e")}}(),d.cursor=d.limit_backward,function(){for(var e,r;r=d.cursor,d.bra=r,e=d.find_among(u,4);)switch(d.ket=d.cursor,e){case 1:d.slice_from("i");break;case 2:d.slice_from("u");break;case 3:d.slice_from("y");break;case 4:if(d.cursor>=d.limit)return;d.cursor++}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return s.setCurrent(e),s.stem(),s.getCurrent()}):(s.setCurrent(e),s.stem(),s.getCurrent())}),e.Pipeline.registerFunction(e.fr.stemmer,"stemmer-fr"),e.fr.stopWordFilter=e.generateStopWordFilter("ai aie aient aies ait as au aura aurai auraient aurais aurait auras aurez auriez aurions aurons auront aux avaient avais avait avec avez aviez avions avons ayant ayez ayons c ce ceci celà ces cet cette d dans de des du elle en es est et eu eue eues eurent eus eusse eussent eusses eussiez eussions eut eux eûmes eût eûtes furent fus fusse fussent fusses fussiez fussions fut fûmes fût fûtes ici il ils j je l la le les leur leurs lui m ma mais me mes moi mon même n ne nos notre nous on ont ou par pas pour qu que quel quelle quelles quels qui s sa sans se sera serai seraient serais serait seras serez seriez serions serons seront ses soi soient sois soit sommes son sont soyez soyons suis sur t ta te tes toi ton tu un une vos votre vous y à étaient étais était étant étiez étions été étée étées étés êtes".split(" ")),e.Pipeline.registerFunction(e.fr.stopWordFilter,"stopWordFilter-fr")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.hu.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var p,_,n;e.hu=function(){this.pipeline.reset(),this.pipeline.add(e.hu.trimmer,e.hu.stopWordFilter,e.hu.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hu.stemmer))},e.hu.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.hu.trimmer=e.trimmerSupport.generateTrimmer(e.hu.wordCharacters),e.Pipeline.registerFunction(e.hu.trimmer,"trimmer-hu"),e.hu.stemmer=(p=e.stemmerSupport.Among,_=e.stemmerSupport.SnowballProgram,n=new function(){var r,i=[new p("cs",-1,-1),new p("dzs",-1,-1),new p("gy",-1,-1),new p("ly",-1,-1),new p("ny",-1,-1),new p("sz",-1,-1),new p("ty",-1,-1),new p("zs",-1,-1)],n=[new p("á",-1,1),new p("é",-1,2)],a=[new p("bb",-1,-1),new p("cc",-1,-1),new p("dd",-1,-1),new p("ff",-1,-1),new p("gg",-1,-1),new p("jj",-1,-1),new p("kk",-1,-1),new p("ll",-1,-1),new p("mm",-1,-1),new p("nn",-1,-1),new p("pp",-1,-1),new p("rr",-1,-1),new p("ccs",-1,-1),new p("ss",-1,-1),new p("zzs",-1,-1),new p("tt",-1,-1),new p("vv",-1,-1),new p("ggy",-1,-1),new p("lly",-1,-1),new p("nny",-1,-1),new p("tty",-1,-1),new p("ssz",-1,-1),new p("zz",-1,-1)],t=[new p("al",-1,1),new p("el",-1,2)],e=[new p("ba",-1,-1),new p("ra",-1,-1),new p("be",-1,-1),new p("re",-1,-1),new p("ig",-1,-1),new p("nak",-1,-1),new p("nek",-1,-1),new p("val",-1,-1),new p("vel",-1,-1),new p("ul",-1,-1),new p("nál",-1,-1),new p("nél",-1,-1),new p("ból",-1,-1),new p("ról",-1,-1),new p("tól",-1,-1),new p("bõl",-1,-1),new p("rõl",-1,-1),new p("tõl",-1,-1),new p("ül",-1,-1),new p("n",-1,-1),new p("an",19,-1),new p("ban",20,-1),new p("en",19,-1),new p("ben",22,-1),new p("képpen",22,-1),new p("on",19,-1),new p("ön",19,-1),new p("képp",-1,-1),new p("kor",-1,-1),new p("t",-1,-1),new p("at",29,-1),new p("et",29,-1),new p("ként",29,-1),new p("anként",32,-1),new p("enként",32,-1),new p("onként",32,-1),new p("ot",29,-1),new p("ért",29,-1),new p("öt",29,-1),new p("hez",-1,-1),new p("hoz",-1,-1),new p("höz",-1,-1),new p("vá",-1,-1),new p("vé",-1,-1)],s=[new p("án",-1,2),new p("én",-1,1),new p("ánként",-1,3)],c=[new p("stul",-1,2),new p("astul",0,1),new p("ástul",0,3),new p("stül",-1,2),new p("estül",3,1),new p("éstül",3,4)],w=[new p("á",-1,1),new p("é",-1,2)],o=[new p("k",-1,7),new p("ak",0,4),new p("ek",0,6),new p("ok",0,5),new p("ák",0,1),new p("ék",0,2),new p("ök",0,3)],l=[new p("éi",-1,7),new p("áéi",0,6),new p("ééi",0,5),new p("é",-1,9),new p("ké",3,4),new p("aké",4,1),new p("eké",4,1),new p("oké",4,1),new p("áké",4,3),new p("éké",4,2),new p("öké",4,1),new p("éé",3,8)],u=[new p("a",-1,18),new p("ja",0,17),new p("d",-1,16),new p("ad",2,13),new p("ed",2,13),new p("od",2,13),new p("ád",2,14),new p("éd",2,15),new p("öd",2,13),new p("e",-1,18),new p("je",9,17),new p("nk",-1,4),new p("unk",11,1),new p("ánk",11,2),new p("énk",11,3),new p("ünk",11,1),new p("uk",-1,8),new p("juk",16,7),new p("ájuk",17,5),new p("ük",-1,8),new p("jük",19,7),new p("éjük",20,6),new p("m",-1,12),new p("am",22,9),new p("em",22,9),new p("om",22,9),new p("ám",22,10),new p("ém",22,11),new p("o",-1,18),new p("á",-1,19),new p("é",-1,20)],m=[new p("id",-1,10),new p("aid",0,9),new p("jaid",1,6),new p("eid",0,9),new p("jeid",3,6),new p("áid",0,7),new p("éid",0,8),new p("i",-1,15),new p("ai",7,14),new p("jai",8,11),new p("ei",7,14),new p("jei",10,11),new p("ái",7,12),new p("éi",7,13),new p("itek",-1,24),new p("eitek",14,21),new p("jeitek",15,20),new p("éitek",14,23),new p("ik",-1,29),new p("aik",18,26),new p("jaik",19,25),new p("eik",18,26),new p("jeik",21,25),new p("áik",18,27),new p("éik",18,28),new p("ink",-1,20),new p("aink",25,17),new p("jaink",26,16),new p("eink",25,17),new p("jeink",28,16),new p("áink",25,18),new p("éink",25,19),new p("aitok",-1,21),new p("jaitok",32,20),new p("áitok",-1,22),new p("im",-1,5),new p("aim",35,4),new p("jaim",36,1),new p("eim",35,4),new p("jeim",38,1),new p("áim",35,2),new p("éim",35,3)],k=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,17,52,14],f=new _;function b(){return r<=f.cursor}function d(){var e=f.limit-f.cursor;return!!f.find_among_b(a,23)&&(f.cursor=f.limit-e,!0)}function g(){if(f.cursor>f.limit_backward){f.cursor--,f.ket=f.cursor;var e=f.cursor-1;f.limit_backward<=e&&e<=f.limit&&(f.cursor=e,f.bra=e,f.slice_del())}}function h(){f.ket=f.cursor,f.find_among_b(e,44)&&(f.bra=f.cursor,b()&&(f.slice_del(),function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(n,2))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("a");break;case 2:f.slice_from("e")}}()))}this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){return f.getCurrent()},this.stem=function(){var e=f.cursor;return function(){var e,n=f.cursor;if(r=f.limit,f.in_grouping(k,97,252))for(;;){if(e=f.cursor,f.out_grouping(k,97,252))return f.cursor=e,f.find_among(i,8)||(f.cursor=e)=f.limit)return r=e;f.cursor++}if(f.cursor=n,f.out_grouping(k,97,252)){for(;!f.in_grouping(k,97,252);){if(f.cursor>=f.limit)return;f.cursor++}r=f.cursor}}(),f.limit_backward=e,f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(t,2))&&(f.bra=f.cursor,b())){if((1==e||2==e)&&!d())return;f.slice_del(),g()}}(),f.cursor=f.limit,h(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(s,3))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("e");break;case 2:case 3:f.slice_from("a")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(c,6))&&(f.bra=f.cursor,b()))switch(e){case 1:case 2:f.slice_del();break;case 3:f.slice_from("a");break;case 4:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(w,2))&&(f.bra=f.cursor,b())){if((1==e||2==e)&&!d())return;f.slice_del(),g()}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(l,12))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 7:case 9:f.slice_del();break;case 2:case 5:case 8:f.slice_from("e");break;case 3:case 6:f.slice_from("a")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(u,31))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 7:case 8:case 9:case 12:case 13:case 16:case 17:case 18:f.slice_del();break;case 2:case 5:case 10:case 14:case 19:f.slice_from("a");break;case 3:case 6:case 11:case 15:case 20:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(m,42))&&(f.bra=f.cursor,b()))switch(e){case 1:case 4:case 5:case 6:case 9:case 10:case 11:case 14:case 15:case 16:case 17:case 20:case 21:case 24:case 25:case 26:case 29:f.slice_del();break;case 2:case 7:case 12:case 18:case 22:case 27:f.slice_from("a");break;case 3:case 8:case 13:case 19:case 23:case 28:f.slice_from("e")}}(),f.cursor=f.limit,function(){var e;if(f.ket=f.cursor,(e=f.find_among_b(o,7))&&(f.bra=f.cursor,b()))switch(e){case 1:f.slice_from("a");break;case 2:f.slice_from("e");break;case 3:case 4:case 5:case 6:case 7:f.slice_del()}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.hu.stemmer,"stemmer-hu"),e.hu.stopWordFilter=e.generateStopWordFilter("a abban ahhoz ahogy ahol aki akik akkor alatt amely amelyek amelyekben amelyeket amelyet amelynek ami amikor amit amolyan amíg annak arra arról az azok azon azonban azt aztán azután azzal azért be belül benne bár cikk cikkek cikkeket csak de e ebben eddig egy egyes egyetlen egyik egyre egyéb egész ehhez ekkor el ellen elsõ elég elõ elõször elõtt emilyen ennek erre ez ezek ezen ezt ezzel ezért fel felé hanem hiszen hogy hogyan igen ill ill. illetve ilyen ilyenkor ismét ison itt jobban jó jól kell kellett keressünk keresztül ki kívül között közül legalább legyen lehet lehetett lenne lenni lesz lett maga magát majd majd meg mellett mely melyek mert mi mikor milyen minden mindenki mindent mindig mint mintha mit mivel miért most már más másik még míg nagy nagyobb nagyon ne nekem neki nem nincs néha néhány nélkül olyan ott pedig persze rá s saját sem semmi sok sokat sokkal szemben szerint szinte számára talán tehát teljes tovább továbbá több ugyanis utolsó után utána vagy vagyis vagyok valaki valami valamint való van vannak vele vissza viszont volna volt voltak voltam voltunk által általában át én éppen és így õ õk õket össze úgy új újabb újra".split(" ")),e.Pipeline.registerFunction(e.hu.stopWordFilter,"stopWordFilter-hu")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.ja.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(m){if(void 0===m)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===m.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var l="2"==m.version[0];m.ja=function(){this.pipeline.reset(),this.pipeline.add(m.ja.trimmer,m.ja.stopWordFilter,m.ja.stemmer),l?this.tokenizer=m.ja.tokenizer:(m.tokenizer&&(m.tokenizer=m.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=m.ja.tokenizer))};var j=new m.TinySegmenter;m.ja.tokenizer=function(e){var r,t,i,n,o,s,p,a,u;if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return l?new m.Token(e.toLowerCase()):e.toLowerCase()});for(r=(t=e.toString().toLowerCase().replace(/^\s+/,"")).length-1;0<=r;r--)if(/\S/.test(t.charAt(r))){t=t.substring(0,r+1);break}for(o=[],i=t.length,p=a=0;a<=i;a++)if(s=a-p,t.charAt(a).match(/\s/)||a==i){if(0=_.limit||(_.cursor++,!1)}function w(){for(;!_.in_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}for(;!_.out_grouping(m,97,232);){if(_.cursor>=_.limit)return!0;_.cursor++}return!1}function b(){return i<=_.cursor}function p(){return e<=_.cursor}function g(){var r=_.limit-_.cursor;_.find_among_b(t,3)&&(_.cursor=_.limit-r,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del()))}function h(){var r;u=!1,_.ket=_.cursor,_.eq_s_b(1,"e")&&(_.bra=_.cursor,b()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.slice_del(),u=!0,g())))}function k(){var r;b()&&(r=_.limit-_.cursor,_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-r,_.eq_s_b(3,"gem")||(_.cursor=_.limit-r,_.slice_del(),g())))}this.setCurrent=function(r){_.setCurrent(r)},this.getCurrent=function(){return _.getCurrent()},this.stem=function(){var r=_.cursor;return function(){for(var r,e,i,n=_.cursor;;){if(_.bra=_.cursor,r=_.find_among(o,11))switch(_.ket=_.cursor,r){case 1:_.slice_from("a");continue;case 2:_.slice_from("e");continue;case 3:_.slice_from("i");continue;case 4:_.slice_from("o");continue;case 5:_.slice_from("u");continue;case 6:if(_.cursor>=_.limit)break;_.cursor++;continue}break}for(_.cursor=n,_.bra=n,_.eq_s(1,"y")?(_.ket=_.cursor,_.slice_from("Y")):_.cursor=n;;)if(e=_.cursor,_.in_grouping(m,97,232)){if(i=_.cursor,_.bra=i,_.eq_s(1,"i"))_.ket=_.cursor,_.in_grouping(m,97,232)&&(_.slice_from("I"),_.cursor=e);else if(_.cursor=i,_.eq_s(1,"y"))_.ket=_.cursor,_.slice_from("Y"),_.cursor=e;else if(s(e))break}else if(s(e))break}(),_.cursor=r,i=_.limit,e=i,w()||((i=_.cursor)<3&&(i=3),w()||(e=_.cursor)),_.limit_backward=r,_.cursor=_.limit,function(){var r,e,i,n,o,t,s=_.limit-_.cursor;if(_.ket=_.cursor,r=_.find_among_b(c,5))switch(_.bra=_.cursor,r){case 1:b()&&_.slice_from("heid");break;case 2:k();break;case 3:b()&&_.out_grouping_b(f,97,232)&&_.slice_del()}if(_.cursor=_.limit-s,h(),_.cursor=_.limit-s,_.ket=_.cursor,_.eq_s_b(4,"heid")&&(_.bra=_.cursor,p()&&(e=_.limit-_.cursor,_.eq_s_b(1,"c")||(_.cursor=_.limit-e,_.slice_del(),_.ket=_.cursor,_.eq_s_b(2,"en")&&(_.bra=_.cursor,k())))),_.cursor=_.limit-s,_.ket=_.cursor,r=_.find_among_b(a,6))switch(_.bra=_.cursor,r){case 1:if(p()){if(_.slice_del(),i=_.limit-_.cursor,_.ket=_.cursor,_.eq_s_b(2,"ig")&&(_.bra=_.cursor,p()&&(n=_.limit-_.cursor,!_.eq_s_b(1,"e")))){_.cursor=_.limit-n,_.slice_del();break}_.cursor=_.limit-i,g()}break;case 2:p()&&(o=_.limit-_.cursor,_.eq_s_b(1,"e")||(_.cursor=_.limit-o,_.slice_del()));break;case 3:p()&&(_.slice_del(),h());break;case 4:p()&&_.slice_del();break;case 5:p()&&u&&_.slice_del()}_.cursor=_.limit-s,_.out_grouping_b(d,73,232)&&(t=_.limit-_.cursor,_.find_among_b(l,4)&&_.out_grouping_b(m,97,232)&&(_.cursor=_.limit-t,_.ket=_.cursor,_.cursor>_.limit_backward&&(_.cursor--,_.bra=_.cursor,_.slice_del())))}(),_.cursor=_.limit_backward,function(){for(var r;;)if(_.bra=_.cursor,r=_.find_among(n,3))switch(_.ket=_.cursor,r){case 1:_.slice_from("y");break;case 2:_.slice_from("i");break;case 3:if(_.cursor>=_.limit)return;_.cursor++}}(),!0}},function(r){return"function"==typeof r.update?r.update(function(r){return e.setCurrent(r),e.stem(),e.getCurrent()}):(e.setCurrent(r),e.stem(),e.getCurrent())}),r.Pipeline.registerFunction(r.nl.stemmer,"stemmer-nl"),r.nl.stopWordFilter=r.generateStopWordFilter(" aan al alles als altijd andere ben bij daar dan dat de der deze die dit doch doen door dus een eens en er ge geen geweest haar had heb hebben heeft hem het hier hij hoe hun iemand iets ik in is ja je kan kon kunnen maar me meer men met mij mijn moet na naar niet niets nog nu of om omdat onder ons ook op over reeds te tegen toch toen tot u uit uw van veel voor want waren was wat werd wezen wie wil worden wordt zal ze zelf zich zij zijn zo zonder zou".split(" ")),r.Pipeline.registerFunction(r.nl.stopWordFilter,"stopWordFilter-nl")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.no.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var o,s,a=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],m=[new r("dt",-1,-1),new r("vt",-1,-1)],l=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],u=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],d=[119,125,149,1],c=new n;this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var e,r,n,i,t=c.cursor;return function(){var e,r=c.cursor+3;if(s=c.limit,0<=r||r<=c.limit){for(o=r;;){if(e=c.cursor,c.in_grouping(u,97,248)){c.cursor=e;break}if(e>=c.limit)return;c.cursor=e+1}for(;!c.out_grouping(u,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(s=c.cursor)=s&&(r=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,e=c.find_among_b(a,29),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:n=c.limit-c.cursor,c.in_grouping_b(d,98,122)?c.slice_del():(c.cursor=c.limit-n,c.eq_s_b(1,"k")&&c.out_grouping_b(u,97,248)&&c.slice_del());break;case 3:c.slice_from("er")}}(),c.cursor=c.limit,r=c.limit-c.cursor,c.cursor>=s&&(e=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,c.find_among_b(m,2)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e),c.cursor=c.limit,c.cursor>=s&&(i=c.limit_backward,c.limit_backward=s,c.ket=c.cursor,(n=c.find_among_b(l,11))?(c.bra=c.cursor,c.limit_backward=i,1==n&&c.slice_del()):c.limit_backward=i),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.pt.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var j,C,r;e.pt=function(){this.pipeline.reset(),this.pipeline.add(e.pt.trimmer,e.pt.stopWordFilter,e.pt.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.pt.stemmer))},e.pt.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.pt.trimmer=e.trimmerSupport.generateTrimmer(e.pt.wordCharacters),e.Pipeline.registerFunction(e.pt.trimmer,"trimmer-pt"),e.pt.stemmer=(j=e.stemmerSupport.Among,C=e.stemmerSupport.SnowballProgram,r=new function(){var s,n,i,o=[new j("",-1,3),new j("ã",0,1),new j("õ",0,2)],a=[new j("",-1,3),new j("a~",0,1),new j("o~",0,2)],r=[new j("ic",-1,-1),new j("ad",-1,-1),new j("os",-1,-1),new j("iv",-1,1)],t=[new j("ante",-1,1),new j("avel",-1,1),new j("ível",-1,1)],u=[new j("ic",-1,1),new j("abil",-1,1),new j("iv",-1,1)],w=[new j("ica",-1,1),new j("ância",-1,1),new j("ência",-1,4),new j("ira",-1,9),new j("adora",-1,1),new j("osa",-1,1),new j("ista",-1,1),new j("iva",-1,8),new j("eza",-1,1),new j("logía",-1,2),new j("idade",-1,7),new j("ante",-1,1),new j("mente",-1,6),new j("amente",12,5),new j("ável",-1,1),new j("ível",-1,1),new j("ución",-1,3),new j("ico",-1,1),new j("ismo",-1,1),new j("oso",-1,1),new j("amento",-1,1),new j("imento",-1,1),new j("ivo",-1,8),new j("aça~o",-1,1),new j("ador",-1,1),new j("icas",-1,1),new j("ências",-1,4),new j("iras",-1,9),new j("adoras",-1,1),new j("osas",-1,1),new j("istas",-1,1),new j("ivas",-1,8),new j("ezas",-1,1),new j("logías",-1,2),new j("idades",-1,7),new j("uciones",-1,3),new j("adores",-1,1),new j("antes",-1,1),new j("aço~es",-1,1),new j("icos",-1,1),new j("ismos",-1,1),new j("osos",-1,1),new j("amentos",-1,1),new j("imentos",-1,1),new j("ivos",-1,8)],m=[new j("ada",-1,1),new j("ida",-1,1),new j("ia",-1,1),new j("aria",2,1),new j("eria",2,1),new j("iria",2,1),new j("ara",-1,1),new j("era",-1,1),new j("ira",-1,1),new j("ava",-1,1),new j("asse",-1,1),new j("esse",-1,1),new j("isse",-1,1),new j("aste",-1,1),new j("este",-1,1),new j("iste",-1,1),new j("ei",-1,1),new j("arei",16,1),new j("erei",16,1),new j("irei",16,1),new j("am",-1,1),new j("iam",20,1),new j("ariam",21,1),new j("eriam",21,1),new j("iriam",21,1),new j("aram",20,1),new j("eram",20,1),new j("iram",20,1),new j("avam",20,1),new j("em",-1,1),new j("arem",29,1),new j("erem",29,1),new j("irem",29,1),new j("assem",29,1),new j("essem",29,1),new j("issem",29,1),new j("ado",-1,1),new j("ido",-1,1),new j("ando",-1,1),new j("endo",-1,1),new j("indo",-1,1),new j("ara~o",-1,1),new j("era~o",-1,1),new j("ira~o",-1,1),new j("ar",-1,1),new j("er",-1,1),new j("ir",-1,1),new j("as",-1,1),new j("adas",47,1),new j("idas",47,1),new j("ias",47,1),new j("arias",50,1),new j("erias",50,1),new j("irias",50,1),new j("aras",47,1),new j("eras",47,1),new j("iras",47,1),new j("avas",47,1),new j("es",-1,1),new j("ardes",58,1),new j("erdes",58,1),new j("irdes",58,1),new j("ares",58,1),new j("eres",58,1),new j("ires",58,1),new j("asses",58,1),new j("esses",58,1),new j("isses",58,1),new j("astes",58,1),new j("estes",58,1),new j("istes",58,1),new j("is",-1,1),new j("ais",71,1),new j("eis",71,1),new j("areis",73,1),new j("ereis",73,1),new j("ireis",73,1),new j("áreis",73,1),new j("éreis",73,1),new j("íreis",73,1),new j("ásseis",73,1),new j("ésseis",73,1),new j("ísseis",73,1),new j("áveis",73,1),new j("íeis",73,1),new j("aríeis",84,1),new j("eríeis",84,1),new j("iríeis",84,1),new j("ados",-1,1),new j("idos",-1,1),new j("amos",-1,1),new j("áramos",90,1),new j("éramos",90,1),new j("íramos",90,1),new j("ávamos",90,1),new j("íamos",90,1),new j("aríamos",95,1),new j("eríamos",95,1),new j("iríamos",95,1),new j("emos",-1,1),new j("aremos",99,1),new j("eremos",99,1),new j("iremos",99,1),new j("ássemos",99,1),new j("êssemos",99,1),new j("íssemos",99,1),new j("imos",-1,1),new j("armos",-1,1),new j("ermos",-1,1),new j("irmos",-1,1),new j("ámos",-1,1),new j("arás",-1,1),new j("erás",-1,1),new j("irás",-1,1),new j("eu",-1,1),new j("iu",-1,1),new j("ou",-1,1),new j("ará",-1,1),new j("erá",-1,1),new j("irá",-1,1)],c=[new j("a",-1,1),new j("i",-1,1),new j("o",-1,1),new j("os",-1,1),new j("á",-1,1),new j("í",-1,1),new j("ó",-1,1)],l=[new j("e",-1,1),new j("ç",-1,2),new j("é",-1,1),new j("ê",-1,1)],f=[17,65,16,0,0,0,0,0,0,0,0,0,0,0,0,0,3,19,12,2],d=new C;function v(){if(d.out_grouping(f,97,250)){for(;!d.in_grouping(f,97,250);){if(d.cursor>=d.limit)return!0;d.cursor++}return!1}return!0}function p(){var e,r,s=d.cursor;if(d.in_grouping(f,97,250))if(e=d.cursor,v()){if(d.cursor=e,function(){if(d.in_grouping(f,97,250))for(;!d.out_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}return i=d.cursor,!0}())return}else i=d.cursor;if(d.cursor=s,d.out_grouping(f,97,250)){if(r=d.cursor,v()){if(d.cursor=r,!d.in_grouping(f,97,250)||d.cursor>=d.limit)return;d.cursor++}i=d.cursor}}function _(){for(;!d.in_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}for(;!d.out_grouping(f,97,250);){if(d.cursor>=d.limit)return!1;d.cursor++}return!0}function h(){return i<=d.cursor}function b(){return s<=d.cursor}function g(){var e;if(d.ket=d.cursor,!(e=d.find_among_b(w,45)))return!1;switch(d.bra=d.cursor,e){case 1:if(!b())return!1;d.slice_del();break;case 2:if(!b())return!1;d.slice_from("log");break;case 3:if(!b())return!1;d.slice_from("u");break;case 4:if(!b())return!1;d.slice_from("ente");break;case 5:if(!(n<=d.cursor))return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(r,4))&&(d.bra=d.cursor,b()&&(d.slice_del(),1==e&&(d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,b()&&d.slice_del()))));break;case 6:if(!b())return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(t,3))&&(d.bra=d.cursor,1==e&&b()&&d.slice_del());break;case 7:if(!b())return!1;d.slice_del(),d.ket=d.cursor,(e=d.find_among_b(u,3))&&(d.bra=d.cursor,1==e&&b()&&d.slice_del());break;case 8:if(!b())return!1;d.slice_del(),d.ket=d.cursor,d.eq_s_b(2,"at")&&(d.bra=d.cursor,b()&&d.slice_del());break;case 9:if(!h()||!d.eq_s_b(1,"e"))return!1;d.slice_from("ir")}return!0}function k(e,r){if(d.eq_s_b(1,e)){d.bra=d.cursor;var s=d.limit-d.cursor;if(d.eq_s_b(1,r))return d.cursor=d.limit-s,h()&&d.slice_del(),!1}return!0}function q(){if(!g()&&(d.cursor=d.limit,!function(){var e,r;if(d.cursor>=i){if(r=d.limit_backward,d.limit_backward=i,d.ket=d.cursor,e=d.find_among_b(m,120))return d.bra=d.cursor,1==e&&d.slice_del(),d.limit_backward=r,!0;d.limit_backward=r}return!1}()))return d.cursor=d.limit,d.ket=d.cursor,void((e=d.find_among_b(c,7))&&(d.bra=d.cursor,1==e&&h()&&d.slice_del()));var e;d.cursor=d.limit,d.ket=d.cursor,d.eq_s_b(1,"i")&&(d.bra=d.cursor,d.eq_s_b(1,"c")&&(d.cursor=d.limit,h()&&d.slice_del()))}this.setCurrent=function(e){d.setCurrent(e)},this.getCurrent=function(){return d.getCurrent()},this.stem=function(){var e,r=d.cursor;return function(){for(var e;;){if(d.bra=d.cursor,e=d.find_among(o,3))switch(d.ket=d.cursor,e){case 1:d.slice_from("a~");continue;case 2:d.slice_from("o~");continue;case 3:if(d.cursor>=d.limit)break;d.cursor++;continue}break}}(),d.cursor=r,e=d.cursor,i=d.limit,s=n=i,p(),d.cursor=e,_()&&(n=d.cursor,_()&&(s=d.cursor)),d.limit_backward=r,d.cursor=d.limit,q(),d.cursor=d.limit,function(){var e;if(d.ket=d.cursor,e=d.find_among_b(l,4))switch(d.bra=d.cursor,e){case 1:h()&&(d.slice_del(),d.ket=d.cursor,d.limit,d.cursor,k("u","g")&&k("i","c"));break;case 2:d.slice_from("c")}}(),d.cursor=d.limit_backward,function(){for(var e;;){if(d.bra=d.cursor,e=d.find_among(a,3))switch(d.ket=d.cursor,e){case 1:d.slice_from("ã");continue;case 2:d.slice_from("õ");continue;case 3:if(d.cursor>=d.limit)break;d.cursor++;continue}break}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return r.setCurrent(e),r.stem(),r.getCurrent()}):(r.setCurrent(e),r.stem(),r.getCurrent())}),e.Pipeline.registerFunction(e.pt.stemmer,"stemmer-pt"),e.pt.stopWordFilter=e.generateStopWordFilter("a ao aos aquela aquelas aquele aqueles aquilo as até com como da das de dela delas dele deles depois do dos e ela elas ele eles em entre era eram essa essas esse esses esta estamos estas estava estavam este esteja estejam estejamos estes esteve estive estivemos estiver estivera estiveram estiverem estivermos estivesse estivessem estivéramos estivéssemos estou está estávamos estão eu foi fomos for fora foram forem formos fosse fossem fui fôramos fôssemos haja hajam hajamos havemos hei houve houvemos houver houvera houveram houverei houverem houveremos houveria houveriam houvermos houverá houverão houveríamos houvesse houvessem houvéramos houvéssemos há hão isso isto já lhe lhes mais mas me mesmo meu meus minha minhas muito na nas nem no nos nossa nossas nosso nossos num numa não nós o os ou para pela pelas pelo pelos por qual quando que quem se seja sejam sejamos sem serei seremos seria seriam será serão seríamos seu seus somos sou sua suas são só também te tem temos tenha tenham tenhamos tenho terei teremos teria teriam terá terão teríamos teu teus teve tinha tinham tive tivemos tiver tivera tiveram tiverem tivermos tivesse tivessem tivéramos tivéssemos tu tua tuas tém tínhamos um uma você vocês vos à às éramos".split(" ")),e.Pipeline.registerFunction(e.pt.stopWordFilter,"stopWordFilter-pt")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.ru.js: -------------------------------------------------------------------------------- 1 | !function(e,n){"function"==typeof define&&define.amd?define(n):"object"==typeof exports?module.exports=n():n()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var h,g,n;e.ru=function(){this.pipeline.reset(),this.pipeline.add(e.ru.trimmer,e.ru.stopWordFilter,e.ru.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ru.stemmer))},e.ru.wordCharacters="Ѐ-҄҇-ԯᴫᵸⷠ-ⷿꙀ-ꚟ︮︯",e.ru.trimmer=e.trimmerSupport.generateTrimmer(e.ru.wordCharacters),e.Pipeline.registerFunction(e.ru.trimmer,"trimmer-ru"),e.ru.stemmer=(h=e.stemmerSupport.Among,g=e.stemmerSupport.SnowballProgram,n=new function(){var n,e,r=[new h("в",-1,1),new h("ив",0,2),new h("ыв",0,2),new h("вши",-1,1),new h("ивши",3,2),new h("ывши",3,2),new h("вшись",-1,1),new h("ившись",6,2),new h("ывшись",6,2)],t=[new h("ее",-1,1),new h("ие",-1,1),new h("ое",-1,1),new h("ые",-1,1),new h("ими",-1,1),new h("ыми",-1,1),new h("ей",-1,1),new h("ий",-1,1),new h("ой",-1,1),new h("ый",-1,1),new h("ем",-1,1),new h("им",-1,1),new h("ом",-1,1),new h("ым",-1,1),new h("его",-1,1),new h("ого",-1,1),new h("ему",-1,1),new h("ому",-1,1),new h("их",-1,1),new h("ых",-1,1),new h("ею",-1,1),new h("ою",-1,1),new h("ую",-1,1),new h("юю",-1,1),new h("ая",-1,1),new h("яя",-1,1)],w=[new h("ем",-1,1),new h("нн",-1,1),new h("вш",-1,1),new h("ивш",2,2),new h("ывш",2,2),new h("щ",-1,1),new h("ющ",5,1),new h("ующ",6,2)],i=[new h("сь",-1,1),new h("ся",-1,1)],u=[new h("ла",-1,1),new h("ила",0,2),new h("ыла",0,2),new h("на",-1,1),new h("ена",3,2),new h("ете",-1,1),new h("ите",-1,2),new h("йте",-1,1),new h("ейте",7,2),new h("уйте",7,2),new h("ли",-1,1),new h("или",10,2),new h("ыли",10,2),new h("й",-1,1),new h("ей",13,2),new h("уй",13,2),new h("л",-1,1),new h("ил",16,2),new h("ыл",16,2),new h("ем",-1,1),new h("им",-1,2),new h("ым",-1,2),new h("н",-1,1),new h("ен",22,2),new h("ло",-1,1),new h("ило",24,2),new h("ыло",24,2),new h("но",-1,1),new h("ено",27,2),new h("нно",27,1),new h("ет",-1,1),new h("ует",30,2),new h("ит",-1,2),new h("ыт",-1,2),new h("ют",-1,1),new h("уют",34,2),new h("ят",-1,2),new h("ны",-1,1),new h("ены",37,2),new h("ть",-1,1),new h("ить",39,2),new h("ыть",39,2),new h("ешь",-1,1),new h("ишь",-1,2),new h("ю",-1,2),new h("ую",44,2)],s=[new h("а",-1,1),new h("ев",-1,1),new h("ов",-1,1),new h("е",-1,1),new h("ие",3,1),new h("ье",3,1),new h("и",-1,1),new h("еи",6,1),new h("ии",6,1),new h("ами",6,1),new h("ями",6,1),new h("иями",10,1),new h("й",-1,1),new h("ей",12,1),new h("ией",13,1),new h("ий",12,1),new h("ой",12,1),new h("ам",-1,1),new h("ем",-1,1),new h("ием",18,1),new h("ом",-1,1),new h("ям",-1,1),new h("иям",21,1),new h("о",-1,1),new h("у",-1,1),new h("ах",-1,1),new h("ях",-1,1),new h("иях",26,1),new h("ы",-1,1),new h("ь",-1,1),new h("ю",-1,1),new h("ию",30,1),new h("ью",30,1),new h("я",-1,1),new h("ия",33,1),new h("ья",33,1)],o=[new h("ост",-1,1),new h("ость",-1,1)],c=[new h("ейше",-1,1),new h("н",-1,2),new h("ейш",-1,1),new h("ь",-1,3)],m=[33,65,8,232],l=new g;function f(){for(;!l.in_grouping(m,1072,1103);){if(l.cursor>=l.limit)return!1;l.cursor++}return!0}function a(){for(;!l.out_grouping(m,1072,1103);){if(l.cursor>=l.limit)return!1;l.cursor++}return!0}function p(e,n){var r,t;if(l.ket=l.cursor,r=l.find_among_b(e,n)){switch(l.bra=l.cursor,r){case 1:if(t=l.limit-l.cursor,!l.eq_s_b(1,"а")&&(l.cursor=l.limit-t,!l.eq_s_b(1,"я")))return!1;case 2:l.slice_del()}return!0}return!1}function d(e,n){var r;return l.ket=l.cursor,!!(r=l.find_among_b(e,n))&&(l.bra=l.cursor,1==r&&l.slice_del(),!0)}function _(){return!!d(t,26)&&(p(w,8),!0)}function b(){var e;l.ket=l.cursor,(e=l.find_among_b(o,2))&&(l.bra=l.cursor,n<=l.cursor&&1==e&&l.slice_del())}this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){return e=l.limit,n=e,f()&&(e=l.cursor,a()&&f()&&a()&&(n=l.cursor)),l.cursor=l.limit,!(l.cursor>3]&1<<(7&s))return this.cursor++,!0}return!1},in_grouping_b:function(r,t,i){if(this.cursor>this.limit_backward){var s=b.charCodeAt(this.cursor-1);if(s<=i&&t<=s&&r[(s-=t)>>3]&1<<(7&s))return this.cursor--,!0}return!1},out_grouping:function(r,t,i){if(this.cursor>3]&1<<(7&s)))return this.cursor++,!0}return!1},out_grouping_b:function(r,t,i){if(this.cursor>this.limit_backward){var s=b.charCodeAt(this.cursor-1);if(i>3]&1<<(7&s)))return this.cursor--,!0}return!1},eq_s:function(r,t){if(this.limit-this.cursor>1),a=0,f=u=(l=r[i]).s_size){if(this.cursor=e+l.s_size,!l.method)return l.result;var m=l.method();if(this.cursor=e+l.s_size,m)return l.result}if((i=l.substring_i)<0)return 0}},find_among_b:function(r,t){for(var i=0,s=t,e=this.cursor,n=this.limit_backward,u=0,o=0,h=!1;;){for(var c=i+(s-i>>1),a=0,f=u=(_=r[i]).s_size){if(this.cursor=e-_.s_size,!_.method)return _.result;var m=_.method();if(this.cursor=e-_.s_size,m)return _.result}if((i=_.substring_i)<0)return 0}},replace_s:function(r,t,i){var s=i.length-(t-r);return b=b.substring(0,r)+i+b.substring(t),this.limit+=s,this.cursor>=t?this.cursor+=s:this.cursor>r&&(this.cursor=r),s},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>b.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),b.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.sv.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,l,n;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,l=e.stemmerSupport.SnowballProgram,n=new function(){var n,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new l;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var e,r=m.cursor;return function(){var e,r=m.cursor+3;if(t=m.limit,0<=r||r<=m.limit){for(n=r;;){if(e=m.cursor,m.in_grouping(o,97,246)){m.cursor=e;break}if(m.cursor=e,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,e=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=e),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/lunr.th.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(t){if(void 0===t)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===t.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==t.version[0];t.th=function(){this.pipeline.reset(),this.pipeline.add(t.th.trimmer),i?this.tokenizer=t.th.tokenizer:(t.tokenizer&&(t.tokenizer=t.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=t.th.tokenizer))},t.th.wordCharacters="[฀-๿]",t.th.trimmer=t.trimmerSupport.generateTrimmer(t.th.wordCharacters),t.Pipeline.registerFunction(t.th.trimmer,"trimmer-th");var n=t.wordcut;n.init(),t.th.tokenizer=function(e){if(!arguments.length||null==e||null==e)return[];if(Array.isArray(e))return e.map(function(e){return i?new t.Token(e):e});var r=e.toString().replace(/^\s+/,"");return n.cut(r).split("|")}}}); -------------------------------------------------------------------------------- /site/assets/javascripts/modernizr.74668098.js: -------------------------------------------------------------------------------- 1 | !function(e,t){for(var n in t)e[n]=t[n]}(window,function(n){var r={};function o(e){if(r[e])return r[e].exports;var t=r[e]={i:e,l:!1,exports:{}};return n[e].call(t.exports,t,t.exports,o),t.l=!0,t.exports}return o.m=n,o.c=r,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=11)}({11:function(e,t,n){"use strict";n.r(t);n(12)},12:function(e,t){var n;(function(i,d,p){function y(e,t){return typeof e===t}function s(e){var t=S.className,n=c._config.classPrefix||"";if(b&&(t=t.baseVal),c._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}c._config.enableClasses&&(0 2 | 3 | 4 | None 5 | 2019-09-22 6 | daily 7 | 8 | 9 | None 10 | 2019-09-22 11 | daily 12 | 13 | 14 | None 15 | 2019-09-22 16 | daily 17 | 18 | 19 | None 20 | 2019-09-22 21 | daily 22 | 23 | 24 | None 25 | 2019-09-22 26 | daily 27 | 28 | 29 | None 30 | 2019-09-22 31 | daily 32 | 33 | 34 | None 35 | 2019-09-22 36 | daily 37 | 38 | 39 | None 40 | 2019-09-22 41 | daily 42 | 43 | 44 | None 45 | 2019-09-22 46 | daily 47 | 48 | 49 | None 50 | 2019-09-22 51 | daily 52 | 53 | 54 | None 55 | 2019-09-22 56 | daily 57 | 58 | 59 | None 60 | 2019-09-22 61 | daily 62 | 63 | -------------------------------------------------------------------------------- /site/sitemap.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apptio/kr8/5fde2b5d3ae8dbc7fe77b5d179738e20d9c2fc70/site/sitemap.xml.gz --------------------------------------------------------------------------------